2011-04-09 3 views
9

J'ai essayé l'implémentation de la liste d'initialisation C++ 0x de ma version G ++ mais elle ne génère que des lignes vides.Pourquoi cette utilisation d'initializer_list se comporte-t-elle mal lors de la transmission de chaînes?

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

Je n'ai aucune idée de ce que j'ai fait de mal. Est-ce que quelqu'un peut m'aider s'il vous plaît?

Répondre

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

Si je déclare que:

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

il travaille: http://ideone.com/21mvL

Mais qui est bizarre. On dirait que c'est un bug de compilateur.


EDIT:

Son certainement un bug du compilateur, parce que si j'écris (*it).c_str() il imprime les cordes !!

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

+4

Cette affiche la chaîne de ' "bonjour"' aussi: http://ideone.com/C9Q7p -.- –

+0

@Johannes: Si vous supprimer 'c_str()', il n'imprime pas "" bonjour "': http://ideone.com/NTRUh ... et je suis confus. Qu'est-ce qui va pas avec ça? – Nawaz

+1

C'est parce que vous travaillez avec une référence à la variable locale (qui sort de la portée lorsque la fonction retourne). Lorsque vous utilisez c_str(), vous êtes juste chanceux (ou malchanceux, selon le point de vue) que la mémoire contienne toujours une référence à la chaîne 'char *' et que la zone de tas n'a pas encore été écrasée. :) – Vitus

3

On dirait que vous créez deux listes de initialiseur dans l'exemple ci-dessus. Temporairement {"hello", "stackoverflow"} et std::initializer_list<std::string> a.

Sur gcc, les listes d'initialisation {} sont en fait des tableaux temporaires dont la durée de vie prend fin après une instruction complète (sauf si elle est liée directement à std::initializer_list comme dans la ligne commentée de l'exemple ci-dessous). La durée de vie du tableau interne de la première liste se termine juste après le retour du constructeur de a. Le tableau de a pointe alors vers une mémoire invalide (gcc ne copie que le pointeur). Vous pouvez vérifier que les destructeurs std::string sont appelés avant d'entrer dans la boucle.

Et lorsque vous arrivez à boucler, vous lisez la mémoire invalide.

Selon le dernier brouillon standard (n3242), §18.9/1, les listes d'initialisation ne peuvent même pas être copiées comme cela (elles ne fournissent aucun constructeur avec des paramètres).

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

Avec gcc 4.5.0, je reçois

dtor 
dtor 
after a's construction 
Questions connexes