Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding reference to an object before construction

Tags:

Is the behavior of the following code well-defined?

struct X { int i; }; // trivial
struct Y : X { Y(){} }; // non-trivial

extern X xobj;
int& r1 = xobj.i; // #1
X xobj;

extern Y yobj;
Y& r2 = yobj;     // #2
// int& r3 = yobj.i; // #3 - this is UB according to the standard
Y yobj;

This code is inspired by the example in the C++ standard, namely draft N4140 [class.cdtor]/1.

That's what that paragraph reads:

For an object with a non-trivial constructor, referring to any non-static member or base class of the object before the constructor begins execution results in undefined behavior. For an object with a non-trivial destructor, referring to any non-static member or base class of the object after the destructor finishes execution results in undefined behavior.

An example follows, which shows how pointers may and may not be bound to objects.

So intuitively it seems that #1 and #2 are well-defined, while #3 invokes UB if uncommented, but, first, examples are not normative, second, there's no mention of references in the example, and third and the most important, the above paragraph doesn't imply that otherwise the behavior is well-defined. Or does it? Or maybe there's another relevant quote in the standard that I missed?

Edit: The answer may (arguably) be yes if the objects have static storage duration, but they can be also local, e.g:

struct A { A(){} };
struct B { B(A&){} };

struct C {
    B b;
    A a;
    C() : b(a) {}
};

int main() {
    C c;
}

Actually this was the initial inspiration for this question, see Circular dependency in constructor initialization list

like image 648
Anton Savin Avatar asked Apr 23 '15 11:04

Anton Savin


1 Answers

The behavior of #2 is definitely well-defined. As mentioned by @dyp, the relevant paragraph is in [basic.life]:

enter image description here

Binding the glvalue yobj to a reference is fine, since its storage lasts throughout the duration of the program ([basic.stc.static]/1) and the reference is bound to a valid object - aliveness aside - which meets the requirement in ([dcl.ref]/5). Similarly, for the second example you showed, as long as no operation is performed on members of the A subobject, the above paragraph applies as well since the constructor of C is called on the allocated storage this refers to.

like image 107
Columbo Avatar answered Oct 12 '22 09:10

Columbo