Можем ли мы переназначить ссылку в C ++? - PullRequest
55 голосов
/ 15 февраля 2012

Я везде читал, что ссылка должна быть инициализирована тут же и не может быть повторно инициализирована снова.

Чтобы проверить мое понимание, я написал следующую небольшую программу. Кажется, что мне действительно удалось переназначить ссылку. Может кто-нибудь объяснить мне, что на самом деле происходит в моей программе?

#include <iostream>
#include <stdio.h>
#include <conio.h>

using namespace std;

int main()
{
    int i = 5, j = 9;

    int &ri = i;
    cout << " ri is : " << ri  <<"\n";

    i = 10;
    cout << " ri is : " << ri  << "\n";

    ri = j; // >>> Is this not reassigning the reference? <<<
    cout << " ri is : " << ri  <<"\n";

    getch();
    return 0;
}

Код компилируется нормально, и вывод такой, как я ожидал:

ri is : 5
ri is : 10
ri is : 9

Ответы [ 5 ]

67 голосов
/ 15 февраля 2012

ri = j; // >>> Is this not reassigning the reference? <<<

Нет, ri все еще является ссылкой на i - вы можете доказать это, напечатав &ri и &i и увидев, что онитот же адрес.

То, что вы сделали, изменили i до ссылка ri.Напечатайте i после, и вы увидите это.

Кроме того, для сравнения, если вы создадите const int &cri = i;, он не позволит вам присвоить это.

9 голосов
/ 15 февраля 2012

Кажется, мне действительно удалось переназначить ссылку.Это правда?

Нет , у вас нет.Вы фактически переназначаете значение и не привязываете ссылку снова.

В вашем примере, когда вы делаете int &ri = i;, ri привязывается к i в течение своего времени жизни.Когда вы делаете ri = j;, вы просто присваиваете значение j для ri.ri по-прежнему остается ссылкой на i!И это приводит к тому же результату, как если бы вы вместо этого написали i = j;

Если вы хорошо понимаете указатели, тогда всегда думайте о ссылке как о аналогичной интерпретации T* const, где T - это любой тип.

4 голосов
/ 15 февраля 2012

Когда вы назначаете что-либо для ссылки, вы фактически присваиваете значение объекту, с которым связана ссылка. Итак, это:

ri=j;

имеет тот же эффект, что и

i = j;

будет иметь, потому что ri связан с i. Таким образом, любое действие на ri выполняется на i.

3 голосов
/ 15 февраля 2012

Вы не переназначаете ссылку при выполнении ri = j;. Вы фактически присваиваете j i. Попробуйте напечатать i после строки, и вы увидите, что i изменило значение.

1 голос
/ 17 ноября 2017

OP запросил изменение ссылочного объекта путем назначения ссылки, и ему очень правильно сказали, что это изменило ссылочный объект, а не ссылку.Теперь я сделал более острую попытку действительно изменить ссылку и нашел потенциально неприятные вещи.Сначала код.Он пытается переназначить ссылку на новый созданный объект, затем изменяет ссылку, то есть ссылочный объект, обнаруживает, что это не отражено в явно ссылочных объектах, и приходит к выводу, что в C ++ может быть случай висячего указателя.Извините за наспех составленный код.

using namespace std;
vector<int>myints;

auto &i = myints.emplace_back();   // allocate and reference new int in vector
auto myintsaddr = &myints; auto myintfrontaddr = &myints.front(); // for future reference
i = 1;                             // assign a value to the new int through reference
cout << hex << "address of i: 0x" << &i << " equals " << "address of 
myints.back(): 0x" << &myints.back() << '.' << endl;  // check reference as expected
i = myints.emplace_back();     // allocate new int in vector and assign to old reference variable
i = 2;                         // give another value to i
cout << "i=" << i << ", myints={" << myints[0] << ", "<< myints[1] << '}' << endl; // any change to potentially referenced objects?
cout << hex << "&i: 0x" << &i << " unequal to " << "&myints.back(): 0x" << &myints.back() << " as well as &myints.front(): 0x" << &myints.front() << endl;
cout << "Myints " << (myintsaddr== &myints?"not ":"") << "relocated from " << myintsaddr << " to " << &myints << endl;
cout << "Myints front() " << (myintfrontaddr == &myints.front() ? "not " : "") << "relocated from " << myintfrontaddr << " to " << &myints.front() << endl;

Вывод:

address of i: 0x0063C1A0 equals address of myints.back(): 0x0063C1A0.
i=2, myints={1, 0}
&i: 0x0063C1A0 unequal to &myints.back(): 0x0063F00C as well as &myints.front(): 0x0063F008
Myints not relocated from 0039FE48 to 0039FE48
Myints front() relocated from 0063C1A0 to 0063F008

Вывод: по крайней мере, в моем случае (VS2017) ссылка сохранила в памяти точно такой же адрес, носсылочные значения (часть вектора) были перераспределены в другом месте.Ссылка, я могу быть болтался.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...