dimanche 4 octobre 2015

Is it defined behavior to reference an early member from a later member expression during aggregate initialization?

Consider the following:

struct mystruct
{
    int i;
    int j;
};

int main(int argc, char* argv[])
{
    mystruct foo{45, foo.i};   

    cout << foo.i << ", " << foo.j << endl;

    return 0;
}

Note the use of foo.i in the aggregate-initializer list.

g++ 5.2.0 outputs

45, 45

Is this well-defined behavior? Is foo.i in this aggregate-initializer always guaranteed to refer to the being-created structure's i element (and &foo.i would refer to that memory address, for example)?

If I add an explicit constructor to mystruct:

    mystruct(int i, int j) : i(i), j(j) { }

Then I get the following warnings:

main.cpp:15:20: warning: 'foo.a::i' is used uninitialized in this function [-Wuninitialized]
     a foo{45, foo.i};
                ^
main.cpp:19:34: warning: 'foo.a::i' is used uninitialized in this function [-Wuninitialized]
     cout << foo.i << ", " << foo.j << endl;

The code compiles and the output is:

45, 0

Clearly this does something different, and I'm assuming this is undefined behavior. Is it? If so, why the difference between this and when there was no constructor? And, how can I get the initial behavior (if it was well-defined behavior) with a user-defined constructor?

Aucun commentaire:

Enregistrer un commentaire