Please consider this simplified c++14 program:
#include <iostream>
struct A
{
A() { std::cout << "A() "; }
~A() { std::cout << "~A() "; }
};
int main()
{
auto l = std::initializer_list<A>{A()};
std::cout << ". ";
}
https://gcc.godbolt.org/z/1GWvGfxne
GCC prints here
A() . ~A()
Meaning that std::initializer_list
is destructed at the end of scope.
Clang prints:
A() ~A() .
Destroying std::initializer_list
in the line where it is constructed.
Are both compiler behave correctly here or one of them is wrong?
It's subtle.
A std::initializer_list
is backed by an underlying array (produced by the compiler). This array is a like a temporary object, and the std::initializer_list
is a sort of reference type that binds to it. So it will extend the temporary array's lifetime so long as the "reference" exist.
In C++14, we do not have guaranteed copy elision. So what should happen is as though std::initializer_list<A>{A()}
produced a temporary initializer_list
, bound another temporary array to it, and copied the temporary initializer_list
to l
.
std::initializer_list
behaves like a regular reference, as far as lifetime extension is concerned. Only the original reference extends the lifetime, and our original is temporary itself. So the underlying array goes out of existence at the end of the full expression containing the initialization of l
. Clang is the correct one.
Direct-initialization ...
std::initializer_list<A> l {A()};
... produces the same output on both compilers.
Meanwhile, your original code behaves the same on GCC and Clang when compiling for C++17.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With