2012-02-15 2 views
40

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

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

#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 

ответ

42

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

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

Что вы сделали, это изменение iчерез Ссылка ri. Распечатайте i после, и вы увидите это.

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

+0

Почему 'const int & cri = i' не разрешено? На какой строке вы не можете написать это? Причина для компилятора позволяет вставить такую ​​строку в любом месте. Кроме того, это четкий и краткий ответ! – mercury0114

+0

Я не сказал, что это не допустимо - как вы заметили, принятие константы ref к неконстантной переменной в порядке. Я сказал, что не разрешаю вам назначать это_, то есть вы не можете изменить исходную переменную через const ref, как OP с помощью 'ri'. – Useless

+0

О, хорошо, теперь я понимаю, что вы имели в виду. – mercury0114

3

При назначении что-то ссылки вы на самом деле присвоить значение объекту ссылка привязана к. Так что это:

ri=j; 

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

i = j; 

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

3

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

6

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

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

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

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

0

ОП запросил изменение объекта ссылки путем присвоения ссылки и был очень правильно сказано, что это изменило ссылочный объект, а не ссылку. Теперь я сделал более острую попытку по-настоящему изменить ссылку и нашел потенциально неприятный материал. Сначала код. Он пытается переназначить ссылочный var новым созданным объектом, а затем изменяет ссылку, называемую ссылочным объектом, обнаруживает, что это не отражается в объектах, на которые ссылаются ссылки, и приходит к выводу, что у нас может быть случай оборванного указателя на 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) ссылка сохранил тот же самый адрес в памяти, но ссылочные значения (часть вектора), были перераспределены в другом месте. Ссылка i может свисать.

Смежные вопросы