2012-11-01 2 views
20

Considérez ce qui suit:Est-il prudent d'utiliser emplace_back avec un conteneur de unique_ptrs?

std::vector<std::unique_ptr<int>> ptrsToInts; 
ptrsToInts.emplace_back(new int); 

Si réallocation se produit dans le vecteur, et qui échoue (jeter std::bad_alloc), je suis « sûr » ou vais-je fuir un int?

C++ 11 23.3.6.5 [vector.modifiers]/1 dit:

Si une exception est levée autrement que par le constructeur de copier, déplacer constructeur, opérateur d'affectation, ou déplacer opérateur d'affectation de T ou par toute opération InputIterator il n'y a pas d'effets.

ce qui semble indiquer qu'il s'agit d'un problème potentiel. C'est-à-dire, s'il n'y a "aucun effet", alors aucun unique_ptr n'a été construit, et par conséquent le comportement de destructeur sur lequel on compterait delete ce pointeur ne se produirait pas. (Qui pourrait indiquer que emplace_back devrait être interdit pour les conteneurs de unique_ptr s)

+1

Bon point. Cela m'a poussé à abandonner totalement l'utilisation de 'new' en faveur de' std :: make_unique', de sorte que je puisse savoir que chaque allocation se termine par un pointeur intelligent dès le départ. – GManNickG

+0

J'ai noté cet écueil dans un commentaire ici: http://stackoverflow.com/questions/3283778/why-can-i-not-push-back-a-unique-ptr-into-a-vector/3283795#3283795 –

Répondre

18

Si la réallocation est requise et qu'elle échoue, alors oui, votre objet n'est jamais entré dans le conteneur et sera donc perdu.

Cependant, il convient de noter qu'il s'agit d'une erreur purement utilisateur. emplace_back ne devrait pas être "banni" pour les conteneurs de unique_ptr, car il existe des moyens parfaitement sûrs de le faire (tels que reserve ing l'espace à l'avance, de sorte que vous savez qu'il sera toujours là). En outre, vous pouvez passer en entier unique_ptr s, car il est parfaitement capable d'utiliser un constructeur de mouvement.

Donc vraiment, c'est votre faute si vous n'avez pas correctement enveloppé votre objet non-RAII (le int*) dans un objet RAII avant le point où vous pouviez lancer des exceptions.

+2

Ah - mais l'objet ne l'a jamais fait. L'emplacement construit l'objet en place à l'intérieur du bloc de mémoire vectoriel lui-même. Ce qui est passé est un pointeur, pas un 'unique_ptr'. Bien sûr, le pointeur est détruit, mais ai-je la garantie que le destructeur de 'unique_ptr' s'exécute et supprime le pointeur? –

+0

En fait, le fait que le 'emplace' soit un no-op pour une exception indique plutôt que le' int' ne reçoit pas 'delete'd correctement, car son allocation se produit complètement en dehors du' emplace', alors que la construction du) pointeur intelligent arrive à l'intérieur. –

+1

Euh, depuis quand faut-il assigner un "défaut" ici? Pour ce qui est des moyens «parfaitement sûrs» de le faire, il existe des moyens «sûrs» de le faire. Mais si vous forcez l'utilisation d'un constructeur de déplacement, vous pouvez tout simplement utiliser 'push_back' à la place, car il applique le comportement correct dans tous les cas. –

Questions connexes