What is the underlying structure of std::initializer_list?
Asked Answered
M

1

6

First part :

std::initializer_list is a really helpful feature of C++11, so I wondered how it is implemented in the standard library. From what I read here, the compiler creates an array of type T and gives the pointer to the initializer_list<T>.

It also states that copying an initializer_list will create a new object referencing the same data : why is it so ? I would have guessed that it either :

  • copies the data for the new initializer_list
  • moves ownership of the data to the new initializer_list

Second part :

From just one of many online references for the std::vector constructors:

vector (initializer_list<value_type> il,
    const allocator_type& alloc = allocator_type());

(6) initializer list constructor

Constructs a container with a copy of each of the elements in il, in the same order.

I am not comfortable with move semantics yet, but couldn't the data of il be moved to the vector ? I am not aware of the deep implementation of std::vector but IIRC it uses plain-old arrays.

Mcatee answered 3/6, 2013 at 10:21 Comment(8)
Seems like another reason not to trust cplusplus.com. Delving into the standard, one eventually arrives at the initialiser-list ctor calling the pair-of-iterators ctor, which (using emplace construction) will move the elements if possible.Band
cplusplus.com is a terrible, terrible site that does harm to the C++ community. Someone should smash the servers hosting it, burn the hard drives, encase them in concrete and sink them to the bottom of the ocean.Collimator
What is the underlying structure of std::initializer_list? Abstracted away from you, for good reason.Abele
I was not referring to cplusplus.com as the reference (Bible), but I thought it was just an online edition of the standard. Thanks for warning about though, what flaws makes it "terrible" ?Mcatee
@Angew I don't like having to defend that site, but it is correct in this case. initializer_list only provides read access to its elements.Moorfowl
@tehinternetsismadeofcatz I haven't perused it since a recent overhaul, but it used to have several errors and code examples that were either actually wrong or suggested bad ideas. I can't speak for the current content; nowadays I use a standard draft or cppreference.com (which is a wiki, so mistakes can be caught and fixed by the community) as my reference.Moorfowl
@R.MartinhoFernandes Ah, my bad. Thanks for correcting me. Seeing as I'm stuck with VS2010's version of C++11 for now, I haven't studied ILs in enough detail to be aware of this.Band
Good question, I still don't see a satisfactory answer. To me, so far, it looks like std::initializer_list is a language feature and the std:: part is misleading to make you think it is a library feature. Even looking at the code of initializer_list there is something strange about it that makes it a special object it seems. In fact in the GCC STL there is a comment that reads: ` // The compiler can call a private constructor.` This reinforces my belief that it is not a normal class. If this is true, I wonder if one can specialize it or extend it.Misshapen
R
12

What is the underlying structure of std::initializer_list?

Most likely, just a pair of pointers, or a pointer and a size. Paragraph 18.9/2 of the C++11 Standard even mentions this in a (non-normative) note:

An object of type initializer_list<E> provides access to an array of objects of type const E. [ Note: A pair of pointers or a pointer plus a length would be obvious representations for initializer_list. initializer_list is used to implement initializer lists as specified in 8.5.4. Copying an initializer list does not copy the underlying elements. —end note ]

Moreover:

I am not comfortable with move semantics yet, but couldn't the data of il be moved to the vector?

No, you can't move from the elements of an initializer_list, since elements of an initializer_list are supposed to be immutable (see the first sentence of the paragraph quoted above). That's also the reason why only const-qualified member functions give you access to the elements.

Regain answered 3/6, 2013 at 10:29 Comment(5)
Do note that technically a constructor such as foo(foo const&&); is a move constructor, and would in fact be called if you wrapped the iterators of an std::initializer_list in std::move_iterators or used some such trickery. Such a constructor can rarely do anything useful (or different from what a standard copy constructor can do) though.Agranulocytosis
@LucDanton: foo(foo const&&)... ew... :) But yes, technically you're correct. Still doesn't change the fact that elements of an initializer_list are meant to be immutable, so that "move constructor" won't be allowed to move anything without causing undefined behavior.Regain
@AndyProwl: An initializer list can also contain variable references. In that case a move ctor moves the data of the referred element. So yes, the list itself is immutable (will always contain the same reference), but the move ctor can be useful.Deprive
@EmilioGaravaglia: Strictly speaking, it cannot contain references, although it can contain reference_wrappers. Then you would have to do: foo x(std::move(static_cast<foo&>(*l.begin())));, which is getting contrived.Regain
@AndyProwl: Yes, very contrived. They are clearly not designed to work that way... The problem is that const is not transitive as the std::immutable concept should be (but not standard yet: see D as an example of language where these two things are well given distinct keywords). This gives this workarounds some (sort of ) citizenship. Good point.Deprive

© 2022 - 2024 — McMap. All rights reserved.