2

Consider:

#include <iostream>
#include <vector>

class A
{
public:
    const int& i;    
};

class B
{
public:
    const std::vector<int>& i;
};

int main()
{
    A a = { 3 };
    std::cout << a.i << std::endl;

    B b = { { 1, 2 } };
    std::cout << b.i[0] << " " << b.i[1] << std::endl;
}

On VS2015 update 3, this crashes in runtime on the last line because the vector b.i is empty; on gcc (4.9.2) this runs OK and shows the expected output (3 1 2). So on VS it 'works' (does what I expected) for an int, but not a vector.

Is this a VS bug or is it just an accident that it works on gcc?

Roel
  • 19,338
  • 6
  • 61
  • 90
  • 2
    It's pretty clearly undefined behavior. You have references bound to temporaries which are destroyed shortly afterwards. "Seems to work" is one possible manifestation of UB. – Igor Tandetnik Jul 15 '16 at 14:13
  • I don't think this is a duplicate of http://stackoverflow.com/questions/2784262/does-a-const-reference-prolong-the-life-of-a-temporary. That question involves constructor call, but this one is about aggregate initialization. – cpplearner Jul 15 '16 at 14:25
  • The draft standard actually has a similar [example](http://www.eel.is/c++draft/class.temporary#6): `struct S { int mi; const std::pair& mp; }; S a { 1, {2,3} };`. – cpplearner Jul 15 '16 at 14:29

2 Answers2

1

The first is OK, temporary's lifetime is extended when assigned to a reference. Second is UB AFAIK, because { { 1, 2 } } is a std::initializer_list<>, not a std::vector<> directly. Prolonging lifetime temporary objects is not transitive (i.e., it lasts till the end of current function, in this case, the constructor), only local ones get prolonged.

lorro
  • 10,687
  • 23
  • 36
1

It works on gcc by accident, because this is definitely undefined behavior.

In order to satisfy B's initialization, the compiler needs to construct a temporary vector<int>. Since the reference to that vector is const, the compiler does not see a problem with using it to initialize B. However, the temporary object becomes invalid as soon as the initialization is over, so accessing it by reference outside of initialization is undefined behavior.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523