Using "new" with initializer_list does not assign string values, while int values work

Viewed 92

It works when I create a variable with std::initializer_list<std::string>:

auto a = std::initializer_list<std::string>{"1", "2", "3", "4"};

enter image description here

But when I create a variable with a pointer to std::initializer_list<std::string>, the values of the pointer are empty:

auto b = new std::initializer_list<std::string>{"1", "2", "3", "4"};

enter image description here

I tried with integer values and both cases work (std::initializer_list<int>{1, 2, 3, 4} and new std::initializer_list<int>{1, 2, 3, 4}).

2 Answers

In the standard (C++17) it says, referring to the array of const std::string which backs the initializer_list:

The array has the same lifetime 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.

In your code the dynamically-allocated initializer-list object is initialized by the array, so this text applies.

The lifetime extension rules for binding a reference to a temporary inside a new-initializer are: (C++17 [class.temporary]/6.3)

A temporary bound to a reference in a new-initializer persists until the completion of the full-expression containing the new-initializer. [Example:

struct S { int mi; const std::pair<int,int>& mp; };
S a { 1, {2,3} };
S* p = new S{ 1, {2,3} }; // Creates dangling reference

So it seems the backing array is destroyed at the end of the line containing the new , so trying to inspect it after that would cause undefined behaviour (meaning you may or may not see what you expect).

So I wrote a full example:

#include <iostream>
#include <string>

void print(std::initializer_list<std::string> &il)
{
    for (auto &s: il) std::cout << s << ' ';
    std::cout << std::endl;
}

int main( void ) {
    auto a = std::initializer_list<std::string>{"1", "2", "3", "4"};
    auto b = new std::initializer_list<std::string>{"5", "6", "7", "8"};

    print (a);
    print (*b);
}

And the compiler told me what was wrong:

$ clang++ std=c++17 so.cpp
so.cpp:12:49: warning: array backing the allocated initializer list will be destroyed at the end of the full-expression
      [-Wdangling-initializer-list]
        auto b = new std::initializer_list<std::string>{"5", "6", "7", "8"};
                                                       ^~~~~~~~~~~~~~~~~~~~
1 warning generated.
Related