Why does this initializer_list use misbehave when passing strings?

1.6k Views Asked by At

I've tried the C++0x initializer-list implementation of my G++ version but it outputs only empty lines.

#include <initializer_list>
#include <iostream>
#include <string>

int main() {
  std::initializer_list<std::string> a({"hello", "stackoverflow"});
  for(auto it = a.begin(), ite = a.end(); it != ite; ++it)
    std::cout << *it << std::endl;
}

I have no idea what I did wrong. Can anyone help me out please?

2

There are 2 best solutions below

0
On

It looks like you're creating two initializer lists in the example above. Temporary {"hello", "stackoverflow"} and std::initializer_list<std::string> a.

On gcc, {} initializer lists are in fact temporary arrays whose lifetime ends after full statement (unless bound directly to std::initializer_list like in the commented line in the example below).

The lifetime of internal array of the first list ends right after a's constructor returns and thus a's array now points to invalid memory (gcc only copies the pointer). You can check, that std::string destructors get called before you enter the loop.

And when you get to loop, you're reading invalid memory.

According to lastest standard draft (n3242), §18.9/1, initializer lists cannot be even copied like that (they provide no constructor with parameters).

#include <initializer_list>
#include <iostream>

class A
{
public:
  A(int)
  { }

  ~A()
  {
    std::cout << "dtor" << std::endl;
  }
};

int main()
{
  std::initializer_list<A> a({A(2), A(3)});
  // vs std::initializer_list<A> a{A(2), A(3)};
  std::cout << "after a's construction" << std::endl;
}

With gcc 4.5.0, I get

dtor
dtor
after a's construction
2
On
std::initializer_list<std::string> a({"hello", "stackoverflow"});

If I declare that as:

std::initializer_list<std::string> a{"hello", "stackoverflow"}; //without ()

then it's working : http://ideone.com/21mvL

But that is weird. Looks like its a compiler bug.


EDIT:

Its most certainly a compiler bug, because if I write (*it).c_str() it prints the strings!!

std::initializer_list<std::string> a({"hello", "stackoverflow"}); //with ()
for(auto it = a.begin(), ite = a.end(); it != ite; ++it)
   std::cout << (*it).c_str() << std::endl;

Code : http://ideone.com/hXr7V