A braced list of values, as in { 1, 2, 3 }, can be given as a single argument to a function or constructor. This list is received by a type called std::initializer_list.
An initializer_list is a lightweight view of an array created implicitly by the compiler from the braced list. The elements are const and once created the size is fixed.
One can write a function that takes an initializer_list and then iterates over it.
#include <iostream>
#include <initializer_list>
void print(std::initializer_list<int> list)
{
// Visit each element in the range directly
for (int x : list)
std::cout << x << ' ';
std::cout << '\n';
}
int main()
{
print({10, 20, 30});
}
The call print({10, 20, 30}) creates a transient array of the three ints, then constructs the initializer_list that points to that array. The range based for loop inside the function iterates over the list and prints each element. The transient array isn't destroyed until the full expression that created it ends, so the dereference inside the function is fine.
It is used by many standard containers in order to ease the construction.
#include <iostream>
#include <vector>
int main()
{
// Use dynamic storage for a resizable sequence
std::vector<int> v{ 1, 2, 3, 4 };
std::cout << v.size() << '\n';
}
The braced list is turned into an initializer_list and given to the vector constructor. The vector then allocates space for the four elements and copies the values. The size of the resulting vector is 4.
It is also possible to assign an initializer_list to a variable but this is in general a mistake.
#include <iostream>
#include <initializer_list>
int main()
{
std::initializer_list<int> list{ 5, 6, 7 };
std::cout << *list.begin() << '\n';
}
A list object is created and then the first element in the list is printed. When that expression ends the temporary array which is used internally to construct the list will be destroyed. The expression ends when the list has been constructed so using the initializer_list after this point will refer to an array which has been destroyed which is undefined behavior. For this reason an initializer_list will almost never be stored as a function parameter but instead will be passed by value.
The member functions size, begin and end return the number of elements and the iterators delimiting them. The elements are const; an initializer_list can never modify what it is viewing.
std::initializer_list thus provides a simple, consistent means of accepting variable number of arguments of the same type. The compiler creates the temporary array, the function accepts a lightweight view of it, and that view is only available during the call.
0 comments
No comments yet. Be the first.