Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this initializer_list use misbehave when passing strings?

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?

like image 293
Johannes Schaub - litb Avatar asked Apr 09 '11 13:04

Johannes Schaub - litb


2 Answers

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
like image 157
Vitus Avatar answered Oct 27 '22 00:10

Vitus


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

like image 45
Nawaz Avatar answered Oct 26 '22 23:10

Nawaz