#include <stdio.h> #include <initializer_list> struct S { S(int) { puts("S(int)"); } ~S() { puts("~S()"); } }; int main() { std::initializer_list<S> ss({42}); // note extra parentheses puts("main"); } Expected output (clang 3.7, MSVC 18.00.21005.1): S(int) ~S() main Observed output (gcc 5.1.0): S(int) main ~S() The same behaviour is observed when the temporary initializer_list is made explicit: std::initializer_list<S> ss = std::initializer_list<S>{42}; Again, gcc lifetime-extends the backing array; MSVC and clang do not.
11.6.4 [dcl.init.list] paragraph 6: The array has the same lifetime as any other temporary object (15.2), except that initializing an initializer_list object from the array extends the lifetime of the array exactly like binding a reference to a temporary. So the array shares the lifetime of the initializer_list.
Yes... but the initializer_list that the array backs is itself temporary; it has lifetime only for the duration of the call to the copy constructor. From https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48562#c6 : > I think that a warning against "({...})" would be useful too > // fine > initializer_list<int> a{1, 2, 3}; > // this is bad > initializer_list<int> b({1, 2, 3}); > Second one is bad because it will destroy the array after initializing 'b', > and won't lengthen the lifetime (because it will use the copy/move > constructor).
Ah wait, guaranteed copy elision since C++17 should fix this, right? So g++ is actually correct now, even if it was wrong before.