2011-04-09 15 views
9

He intentado la implementación de la lista de inicializadores C++ 0x de mi versión de G ++, pero solo muestra líneas vacías.¿Por qué este initializer_list se comporta incorrectamente al pasar cadenas?

#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; 
} 

No tengo idea de lo que hice mal. ¿Puede alguien ayudarme por favor?

Respuesta

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

Si declaran que a medida:

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

entonces está trabajando: http://ideone.com/21mvL

Pero eso es raro. Parece que es un error del compilador.


EDIT:

Su ciertamente un error del compilador, porque si escribo (*it).c_str() muestra todas las cadenas !!

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; 

Código: http://ideone.com/hXr7V

+4

Esto imprime la cadena ' "hola"' demasiado: http://ideone.com/C9Q7p -.- –

+0

@Johannes: Si eliminar 'c_str()', no imprime '" hello "': http://ideone.com/NTRUh ... y estoy confundido. ¿Qué tiene de malo? – Nawaz

+1

Es porque estás trabajando con referencia a la variable local (que sale del alcance cuando la función vuelve). Cuando usas c_str(), tienes suerte (o desafortunadamente, dependiendo del punto de vista) de que la memoria todavía contiene referencia a la cadena 'char *' y que el área del montón todavía no se ha sobrescrito. :) – Vitus

3

Parece que va a crear dos listas de inicializador en el ejemplo anterior. Temporal {"hello", "stackoverflow"} y std::initializer_list<std::string> a.

En gcc, {} las listas de inicializadores son en realidad matrices temporales cuya duración termina después de la instrucción completa (a menos que se vincule directamente a std::initializer_list como en la línea comentada en el ejemplo a continuación).

La vida útil de la matriz interna de la primera lista finaliza justo después de que el constructor a regrese y, por lo tanto, la matriz a apunta a la memoria no válida (gcc solo copia el puntero). Puede verificar que se llame a los destructores std::string antes de ingresar al ciclo.

Y cuando llega al bucle, está leyendo memoria no válida.

Según el último borrador estándar (n3242), §18.9/1, las listas de inicializadores ni siquiera se pueden copiar así (no proporcionan ningún constructor con parámetros).

#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; 
} 

con GCC 4.5.0, consigo

dtor 
dtor 
after a's construction 
Cuestiones relacionadas