This is similar in spirit to a question that was asked and answered for c
. The comments there implied that a precise answer would be different for c++
, so here is a similar question for code written in c++
.
Is the following program well defined?
int f(int& b)
{
b = 42;
return b;
}
int a { f(a) };
It seems all right to me, but on the other hand, how is a
being constructed from a value that is computed by a function, that itself modifies a
? I'm having a chicken-and-egg feeling about this, so an explanation would be nice. For what it's worth, it appears to work.
This seems to be the same question, so here goes; would the answer be different for class types and fundamental types. i.e. Is the following well formed?
struct S { int i; };
S f(S& b)
{
b.i = 42;
return b;
}
S a { f(a) };
Again, for what it's worth, this appears to work as well.
A reference variable provides a new name to an existing variable. It is dereferenced implicitly and does not need the dereferencing operator * to retrieve the value referenced. On the other hand, a pointer variable stores an address. You can change the address value stored in a pointer.
As you know, an address of an object in C++ can be stored either through a reference or through a pointer. Although it might appear that they represent similar concepts, one of the important differences is that you can reassign a pointer to point to a different address, but you cannot do this with a reference.
The behaviour seems to be undefined in C++20. The change was made by P1358, resolving CWG 2256. As defect resolutions are generally retroactive, this code should be considered UB in all versions of C++.
According to [basic.life]/1:
... The lifetime of an object of type
T
begins when:
- storage with the proper alignment and size for type
T
is obtained, and- its initialization (if any) is complete (including vacuous initialization) ...
At the time when f(a)
is called, the object a
has not yet begun its lifetime since its initialization has not completed. According to [basic.life]/7:
Similarly, before the lifetime of an object has started but after the storage which the object will occupy has been allocated ... any glvalue that refers to the original object may be used but only in limited ways. ... The program has undefined behavior if:
- the glvalue is used to access the object ...
Thus, writing to a
before its initialization has completed is UB, even though the storage has already been allocated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With