c++c++11stdarraystdinitializerlist

Why did STL made a(nother) distinction between a std::array and a std::initializer_list


Why is there not only 1 type with the best performance, to define a list at compile time?

The benchmark is clear, the constexpr std::initializer_list is faster, uses even less memory and the IO-reads are astonishingly less over constexpr std::array:

https://build-bench.com/b/1EDAcFjJ6NACk4Pg4tG2nbsEx0A

So why didn't they implement the array subscription methods to std::initializer_list make std::array unnecessary.


Solution

  • The question betrays some misunderstandings about what is going on here.

    std::array is an array object. It is an object whose storage size is the storage for its array elements. std::initializer_list is a pointer to an array (one created by the compiler). You can heap-allocate std::array for example; you cannot heap-allocate std::initializer_list. Well, you can, but you'd just be heap allocating a pointer, which usually isn't helpful. This:

    auto *p = new std::initializer_list<int>{1, 2, 3, 4};
    

    Is broken code, as it heap allocates a pointer to an array temporary created by the compiler. An array temporary that is immediately destroyed at the end of this statement. So you now have a pointer to an array that does not exist, so using *p or p[x] is undefined behavior.

    Doing the same with std::array works fine, because array is an array.

    Furthermore, the purpose of std::initializer_list is not to "define a list at compile time". As the name suggests, the point of the type is to create a list for the purpose of initializing an object. This is why the ultimate source of its data cannot be provided by any means other than a specific piece of C++ grammar, one used specifically to initialize objects: a braced-init-list.

    You can use std::initializer_list as a quick-and-dirty way of just creating an array of values for some purpose. But that's not the point of the type. That's why it doesn't have an operator[]; because functions that can be initialized from a sequence of values don't tend to need that particular operation. They usually only need to walk it from beginning to end.