As per my understanding, C++ does not allow you to re-seat a reference. In other words, you cannot change the object that a reference "refers" to. It's like a constant pointer in that regard (e.g. int* const a = 3;
).
In some code I looked at today, I saw the following:
CMyObject& object = ObjectA().myObject();
// ...
object = ObjectB().myObject();
Immediately my alarm bells went off on the last line of code above. Wasn't the code trying to re-seat a reference? Yet the code compiled.
Then I realised that what the code was doing was simply invoking the assignment operator (i.e. operator=
) to reassign ObjectA
's internal object to ObjectB
's internal object. The object
reference still referred to ObjectA
, it's just that the contents of ObjectA
now matched that of ObjectB
.
My understanding is that the compiler will always generate a default assignment operator if you don't provide one, which does a shallow copy (similar to the default copy constructor).
Since a reference is typed (just like the underlying object that it refers to), doesn't that mean that we will always invoke the assignment operator when at开发者_运维技巧tempting to re-seat a reference, thus preventing the compiler from complaining about this?
I've been racking my brains out trying to come up with an illegal line of code which will incorrectly try to re-seat a reference, to get the compiler to complain.
Can anyone point me to an example of such code?
You can't "reseat" a reference, because it's syntactically impossible. The reference variable you use which refers to the object uses the same semantics as if it was an object (non-reference) variable.
I've been racking my brains out trying to come up with an illegal line of code which will incorrectly try to re-seat a reference, to get the compiler to complain.
const int i = 42;
const int j = 1337;
const int& r = i;
r = j;
The uninitiated might expect the last line to re-seat r
to j
, but instead, the assignment to i
fails.
You can't write portable C++ code to reseat a reference... the compiler tracks where the reference refers to and doesn't allow it to be changed. It's a kind of alias for whatever it refers to, and in some cases the reference value may be incorporated directly into the code at compile time. On some implementations where a particular reference happens to be stored in the form of a pointer, and happens to be looked up at run time, you may be able to use a reinterpret cast to overwrite it with a pointer to another object, but the behaviour is totally undefined and unreliable. For what little it's worth (nothing practically, but perhaps a smidge in assisting understanding of likely implementation), that might look something like:
struct X
{
Y& y_;
X(Y& y) : y_(y) { }
};
...
X x(y1);
*reinterpret_cast<Y**>(&x) = &y2;
My understanding is that the compiler will always generate a default assignment operator if you don't provide one, which does a shallow copy (similar to the default copy constructor).
Since a reference is typed (just like the underlying object that it refers to), doesn't that mean that we will always invoke the assignment operator when attempting to re-seat a reference, thus preventing the compiler from complaining about this?
It's not quite like that. Implicit copy (assignment) performs memberwise copying (not necessarily shallow), and the compiler won't let bad things happen implicitly to reference members.
class X
{
int& ref;
public:
X(int& r): ref(r) {}
};
int main()
{
int i;
X a(i), b(i);
a = b;
}
精彩评论