std :: auto_ptr vers std :: unique_ptr

190

Avec l'arrivée du nouveau standard (et des pièces déjà disponibles dans certains compilateurs), le nouveau type std::unique_ptrest censé remplacer std::auto_ptr.

Leur utilisation se chevauche-t-elle exactement (pour que je puisse faire une recherche / remplacement globale sur mon code (non pas que je le ferais, mais si je le faisais)) ou devrais-je être conscient de certaines différences qui ne sont pas apparentes à la lecture de la documentation?

Aussi, s'il s'agit d'un remplacement direct, pourquoi lui donner un nouveau nom plutôt que simplement améliorer le std::auto_ptr?

Martin York
la source

Réponses:

221

Vous ne pouvez pas effectuer de recherche / remplacement global car vous pouvez copier un auto_ptr(avec des conséquences connues), mais un unique_ptrne peut être déplacé. Tout ce qui ressemble

std::auto_ptr<int> p(new int);
std::auto_ptr<int> p2 = p; 

devra devenir au moins comme ça

std::unique_ptr<int> p(new int);
std::unique_ptr<int> p2 = std::move(p);

Comme pour les autres différences, unique_ptrpeut gérer correctement les tableaux (il appellera delete[], tandis que auto_ptrtentera d'appeler delete.

Cubbi
la source
103
d'un autre côté, faire cette recherche / remplacement n'entraînera que des erreurs de compilation, cela ne cassera pas silencieusement le code pour autant que je puisse voir. Il est donc prudent de le faire si vous
corrigez
7
@jalf: En effet, je ne peux pas penser à un contre-exemple qui serait bien défini avec auto_ptrs et UB avec unique_ptrs.
Cubbi
1
il semble donc que unique_ptr est une amélioration de auto_ptr: supporte le tableau et supprime l'ambiguïté
Baiyan Huang
92

std::auto_ptret std::unique_ptrsont incompatibles dans certains cas et une baisse de remplacement dans d'autres. Donc, aucune recherche / remplacement ne suffit pas. Cependant, après une recherche / remplacement, les erreurs de compilation devraient tout corriger, sauf les cas de coin étranges. La plupart des erreurs de compilation nécessiteront l'ajout d'un fichier std::move.

  • Variable de portée de la fonction:
    100% compatible, tant que vous ne la transmettez pas par valeur à une autre fonction.
  • Type de retour:
    pas 100% compatible mais 99% compatible ne semble pas faux.
  • Paramètre de fonction par valeur:
    100% compatible avec une mise en garde, unique_ptrs doit être passé via un std::moveappel. Celui-ci est simple car le compilateur se plaindra si vous ne le faites pas correctement.
  • Paramètre de fonction par référence:
    100% compatible.
  • Variable de membre de classe:
    celle-ci est délicate. std::auto_ptrLa sémantique de la copie est mauvaise. Si la classe n'autorise pas la copie, std::unique_ptrc'est une baisse de remplacement. Cependant, si vous essayez de donner à la classe une sémantique de copie raisonnable, vous devrez changer le std::auto_ptrcode de gestion. C'est simple car le compilateur se plaindra si vous ne faites pas les choses correctement. Si vous avez autorisé la copie d'une classe avec un std::auto_ptrmembre sans code spécial, alors honte à vous et bonne chance.

En résumé, std::unique_ptrc'est un ininterrompu std::auto_ptr. Il interdit au moment de la compilation les comportements qui étaient souvent des erreurs lors de l'utilisation d'un fichier std::auto_ptr. Donc, si vous avez utilisé std::auto_ptravec le soin dont vous avez besoin, passer à std::unique_ptrdevrait être simple. Si vous vous êtes appuyé sur std::auto_ptrle comportement étrange de 's, vous devez de toute façon refactoriser votre code.

deft_code
la source
8
+1 pour "vous devez quand même refactoriser votre code". Les auto_ptrs ne sont bons que pour ce que 20.4.5 / 3 dit qu'ils sont bons.
Cubbi
8
Permettez-moi d'ajouter à cela que vous devriez, par tous les moyens, remplacer auto_ptr par unique_ptr dans votre code et corriger les erreurs de compilation. Vous seriez surpris du nombre de bogues que cela permettra de découvrir.
Bartosz Milewski
36

AFAIK, unique_ptrn'est pas un remplacement direct. Le principal défaut qu'il corrige est le transfert implicite de propriété.

std::auto_ptr<int> a(new int(10)), b;
b = a; //implicitly transfers ownership

std::unique_ptr<int> a(new int(10)), b;
b = std::move(a); //ownership must be transferred explicitly

D'autre part, unique_ptraura des capacités complètement nouvelles: ils peuvent être stockés dans des conteneurs.

OncleBens
la source
8
Scott Meyers a également mentionné dans son "Effective C ++" (3e édition) Item 13 (page 64) que les conteneurs STL exigent que leur contenu présente un comportement de copie "normal", donc les conteneurs de auto_ptrne sont pas autorisés.
Qiang Xu
32

Herb Sutter a une belle explication sur GotW # 89 :

Quel est le problème avec auto_ptr? auto_ptr est le plus charitablement caractérisé comme une tentative vaillante de créer un unique_ptr avant que C ++ n'ait une sémantique de déplacement. auto_ptr est désormais obsolète et ne doit pas être utilisé dans un nouveau code.

Si vous avez auto_ptr dans une base de code existante, lorsque vous en avez l'occasion, essayez de faire une recherche globale et de remplacer auto_ptr en unique_ptr; la grande majorité des utilisations fonctionneront de la même manière, et cela pourrait exposer (comme une erreur de compilation) ou corriger (silencieusement) un ou deux bogues que vous ne saviez pas que vous aviez.

En d'autres termes, même si une recherche et un remplacement globaux peuvent "casser" votre code temporairement, vous devriez le faire quand même: cela peut prendre un certain temps pour corriger les erreurs de compilation, mais vous évitera beaucoup plus de problèmes à long terme.

Valar Dohaeris
la source
Excellent lien. Merci beaucoup!
fotNelton