3

cppreference says:

The underlying array is a temporary array of type const T[N], in which each element is copy-initialized (except that narrowing conversions are invalid) from the corresponding element of the original initializer list. The lifetime of the underlying array is the same as any other temporary object, except that initializing an initializer_list object from the array extends the lifetime of the array exactly like binding a reference to a temporary (with the same exceptions, such as for initializing a non-static class member). The underlying array may be allocated in read-only memory.

What's the reasoning behind this decision? Why is moving not ok?

What about copy-ellision?

struct A { A(const A&){ std::cout << "Oh no, a copy!\n"; } }; struct B { B(std::initializer_list<A> il); }; int main() { B b{ A{} }; return 0; } 

My compiler ellides the copy. But are these copies guaranteed to be ellided?

4
  • 1
    stackoverflow.com/questions/8193102/… you get a "Probably the reason" in the accepted answer Commented Mar 26, 2020 at 7:52
  • I realized while reading stackoverflow.com/questions/8193102/…, that is even worse. Elements cannot be moved out of the initializer_ list, because the underlying array is of type const T[N]. Commented Mar 26, 2020 at 7:59
  • 1
    It really seems that the copy constructor calls are elided. Before C++17, one can suppress this elision with -fno-elide-constructors GCC flag. Live demo: wandbox.org/permlink/AF6H1RNWtVfkyoOT. Commented Mar 26, 2020 at 8:02
  • I'm not sure if I fully understood the following sentence: "Probably the reason for this is so the compiler can elect to make the initializer_list a statically-initialized constant." from stackoverflow.com/questions/8193102/…. Why and when should the compiler do this? Commented Mar 26, 2020 at 8:05

1 Answer 1

3

"Copy initialization" in C++ doesn't mean things will necessarily be copied. It's just a formal name for the constraints under which initialization will occur. For instance, when copy initializing, explicit c'tors are not candidates. So the following code will be ill-formed

#include <iostream> #include <initializer_list> struct A { explicit A() = default; A(const A&){ std::cout << "Oh no, a copy!\n"; } }; struct B { B(std::initializer_list<A> il); }; int main() { B b{ {} }; return 0; } 

The single member in the list needs to be copy-initialized from {}, which entails calling the default c'tor. However, since the c'tor is marked explicit, this initialization cannot happen.

Copy elision is certainly possible pre-C++17, and is mandatory in C++17 onward in certain contexts. In your example, under a C++17 compiler, since you provide an initializer that is a prvalue (a pure rvalue, not an object), the initialization rules of C++ mandate that the target is initialized directly, without intermediate objects created. Even though the context is called "copy initialization", there are no superfluous objects.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.