When using std::initializer_list
I have experienced some difficulties. It didn't take long to realise that I thought of it more as a container, when in fact it has reference semantics. So my question is, which of the following examples might cause problems and if not, why do they work?
I should add that I'm using VS2013 and std::initializer_list
is implemented using only a begin and end pointer.
Example 1
const auto tmpList = {1, 2, 3};
const vector<int> test(tmpList);
This may work if the literals 1, 2 and 3 are stored in a contiguous block of memory. But is this guaranteed?
Example 2
const string a("foo");
int someOtherVariable = 10;
const string b("bar");
const auto tmpList = {a, b};
const vector<string> test(tmpList);
This should not work, since a and b might be in different places on the stack (remember std::initializer_list
simply keeps a pointer to the first string). But then again, the compiler should be able to handle this somehow, since this should work in my understanding:
const vector<string> test({a, b});
Or does it?
Example 3
const auto tmpList = {string("foo"), string("bar")};
const vector<string> test(tmpList);
In my point of view the initializer list points to already destroyed temporaries when passed to the vector.
Conclusions
I think all these examples show that std::initializer_list
should not be used as a temporary container. If that is the case, shouldn't storing an initializer list anywhere (except as parameter to a function) be prohibited? Maybe I'm also just missing on some compiler magic which sees to it that the pointers always point to valid, contiguous memory.
Solution & Background
It seems all of the above examples are well defined. There seems to be a bug either in my program or in the VS2013 C++ compiler. The problem arose first when I used an initializer list like this:
const auto tmpList = {join(myList1), join(myList2)};
const vector<string> test(tmpList);
join
is a function which returns a std::string
. In this case the initializer list contained 2 entries, but the first one was empty. Splitting it up into this resolves the problem:
const auto str1 = join(myList1);
const auto str2 = join(myList2);
const auto tmpList = {str1, str2};
const vector<string> test(tmpList);
Now that I think of it, it looks like a compiler bug to me, but it led me to believe that the initializer list actually stored pointers directly to the literals, stack variables and so on instead of first copying them to a local array.