Salut,
Quand j'étudiais, j'avais un prof qui n'hésitait jamais à "jouer au compilateur"... je vais faire pareil ici:
fooes.push_back( Foo( "first foo" ) );
ajoutes à fooes un nouvel élément dont la chaine de caractères correspond à "first foo"
Foo & first_foo = fooes.back();
récupère une référence (!!!) sur le dernier élément du vecteur, à savoir, la structure pour laquelle la chaine est "first foo"
Foo & second_foo = first_foo;
crée simplement une autre variable, qui fait référence au même élément
fooes.emplace_back( Foo( "second foo" ) );
ajoute, en utilisant la sémantique de mouvement, un deuxième élément dont la chaine est "second foo".
A priori, cela ne pose pas de problème en soi, sauf que... C'est pour les éléments de fooes que la sémantique de mouvement est utilisée, ce qui, à mon sens, n'empêche en rien le vecteur d'augmenter sa capacité en cas de besoin.
Il est fort vraisemblable que les objets soient placé dans l'espace nouvellement créé par mouvement, mais, quoi qu'il en soit, je dirais que les deux références se réfèrent à des éléments invalides.
second_foo = fooes.back();
récupère le dernier élément de fooes (celle dont la ligne est "second foo").
second_foo fait bel et bien référence à cet objet (qui est tout à fait valide), mais l'opérateur d'affectation n'est pas récursif / transitif.
Pour moi, first_foo fait toujours référence à un objet invalide
cout << "foo1: " << first_foo.name << endl;
A priori, comportement indéterminé parce que first_foo fait référence à un objet invalide.
cout << "foo2: " << second_foo.name << endl;
affiche "second string", quoi qu'il advienne
La seule chose dont je ne sois pas tout à fait sur, c'est le comportement de first_foo dans l'histoire.
J'aurais tendance à dire que, l'objet d'origine ayant de toutes manières été déplacé (que ce soit en utilisant la sémantique de mouvement ne change rien à l'histoire), ou risquant de l'avoir été (tout dépend de la capacité maximale créée par défaut pour ton implémentation spécifique), on ne devrait plus tenter le moindre accès à first_foo car on ne peut pas garantir qu'il n'aura justement pas été déplacé et que la référence soit donc toujours valide.
Les autres types de collections n'auraient sans doute pas posé ce genre de problème car elles sont (en théorie du moins) basées sur des pointeurs permettant de mettre les différents éléments en relation les uns avec les autres, mais std::vector devant de toutes manières assurer la contiguité des données, il est toujours susceptible de devoir (au mieux) déplacer les éléments qu'il contient
Partager