C++ - Why does 2 local references to the same object stay in sync?

2.5k views Asked by At

I would like to understand what's going on here. Obviously, there's some aspect of references or assignment operators that I am not getting right.

Objective: Within a function, I want to work with 2 local reference variables to various elements of the same list: one is the iterated over and one is a "marker" that changes when certain conditions are met. Both are initially referencing the same element. I'm not modifying the strings in the list (in the actual code, the list is a parameter passed by reference).

Problem: as soon as a change the second reference to another element, the first reference now points to that new element as well. The references stay in sync, but I expected them to be independent.

My interpretation: iterator is a pointer to a string that is contained in the list. In string & ref1 = *it, I am dereferencing iterator pointer to get the string address (whether that itself is a pointer shouldn't really matter IMO) so that ref1 and ref2 are "aliases" to the address of string "a". So in my mind, changing ref2 so it points to another string does not change the address of anything, but just the value of ref2 should now point or "alias" to string "b", while ref1 should still points to "a".

Changing the code to use pointers instead of references works perfectly, so it seems I am incorrectly treating reference variables as pointers, or there's something behind the scenes (overloaded assignment operators?) I'm not thinking of.

list<string> l;    
string s1 = "a";   
string s2 = "b";    
l.push_back(s1);    
l.push_back(s2);    
list<string>::iterator it = l.begin();    
string & ref1 = *it;    
string & ref2 = *it;    
++it;    // After this line, both ref1 && ref2 evaluates to "a"
ref2 = *it; // After this line, both ref1 && ref2 evaluates to "b"
if(ref1 == ref2){    
  cout << "woot!" << endl;    
}
2

There are 2 answers

4
David Schwartz On BEST ANSWER
string & ref1 = *it;    
string & ref2 = *it;

Okay, so you create two references to the same string.

++it;    // After this line, both ref1 && ref2 evaluates to "a"

Right, because they are both references to the same string. This is the way you created them.

ref2 = *it; // After this line, both ref1 && ref2 evaluates to "b"

Right, because they are both references to the same string, and you just used one to change the value of the string it referred to.

So in my mind, changing ref2 so it points to another string does not change the address of anything, but just the value of ref2 should now point or "alias" to string "b", while ref1 should still points to "a".

That's not how references work. This is how references work:

int a, b;
int& ref = a;
ref = b; // same as a=b, does not "re-seat" the reference

If you want a reference that can be "re-seated", use std::reference_wrapper.

0
Andreas Haferburg On

A reference is similar to a pointer where you can't change the address that it points to. Assigning to a reference is the same as assigning to the address that it points to, not to the pointer:

int x = 5;
int& xref = x;
// equivalent to:
int* const xptr = &x;

xref = 10;
// equivalent to:
*xptr = 10;