Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it well defined to reference a variable before it's constructed

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.

like image 528
cigien Avatar asked Apr 15 '20 01:04

cigien


People also ask

What is the use of reference variables in c++?

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.

Can you reassign a reference c++?

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.


1 Answers

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.

like image 135
Brian Bi Avatar answered Oct 25 '22 01:10

Brian Bi