Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>This one was warping my mind at first but I think I got it now. As per 12.6.2.5 of 1998 Standard, C++ guarantees that data members are initialized in the order they are declared in the class, and that the constructor body is executed after all members have been initialized. This means that the expression </p> <pre><code>struct A; struct B { A&amp; a; }; struct A { B&amp; b; }; struct {A first; B second;} pair = {pair.second, pair.first}; </code></pre> <p>makes sense since pair is an auto (local, stack) variable, so its relative address and address of members are known to the compiler, AND there are no constructors for first and second. </p> <p>Why the two conditions mean the code above makes sense: when <code>first</code>, of type <code>A</code>, is constructed (before any other data member of <code>pair</code>), <code>first</code>'s data member <code>b</code> is set to reference <code>pair.second</code>, the address of which is known to the compiler because it is a stack variable (space already exists for it in the program, AFAIU). Note that <code>pair.second</code> as an object, ie <strong>memory</strong> segment, has not been initialized (contains garbage), but that doesn't change the fact that the address of that garbage is known at compile time and can be used to set references. Since <code>A</code> has no constructor, it can't attempt to do anything with <code>b</code>, so behavior is well defined. Once <code>first</code> has been initialized, it is the turn of <code>second</code>, and same: its data member <code>a</code> references <code>pair.first</code>, which is of type <code>A</code>, and <code>pair.first</code> address is known by compiler. </p> <p>If the addresses were not known by compiler (say because using heap memory via new operator), there should be compile error, or if not, undefined behavior. Though judicious use of the placement new operator might allow it to work, since then again the addresses of both <code>first</code> and <code>second</code> could be known by the time <code>first</code> is initialized. </p> <p>Now for the variation: </p> <pre><code>struct A; struct B { A&amp; ref; B(A&amp; a) : ref(a) {} }; struct A { B&amp; ref; A(B&amp; b) : ref(b) {} }; struct {B first; A second;} pair = {pair.second, pair.first}; </code></pre> <p>The only difference from first code example is that <code>B</code> constructor is explicitly defined, but the assembly code is surely identical as there is no code in the constructor bodies. So if first code sample works, the second should too. </p> <p>HOWEVER, if there <em>is</em> code in the constructor body of B, which is getting a reference to something (<code>pair.second</code>) that hasn't been initialized yet (but for which address is defined and known), and that code uses <code>a</code>, well clearly you're looking for trouble. If you're lucky you'll get a crash, but writing to <code>a</code> will probably fail silently as the values get later overwritten when <code>A</code> constructor is eventually called. of </p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload