2016-03-16 1 views
6

J'ai une classe qui représente un contexte d'exécution et construit un arbre, la racine de l'arbre est maintenu dans une unique_ptr. Lorsque la construction de l'arbre est terminée, je veux extraire l'arbre. Voici comment il semble (pas runnable, ce n'est pas une question de débogage):std :: unique_ptr :: release() vs std :: move()

class Context { 
    private: 
    std::unique_ptr<Node> root{new Node{}}; 
    public: 
    // imagine a constructor, attributes and methods to build a tree 
    std::unique_ptr<Node> extractTree() { 
     return std::move(this->root); 
    } 
}; 

J'utilisé std::move() pour extraire le nœud racine de l'instance Context.

Cependant, il existe des alternatives à l'utilisation std::move() .: par exemple

std::unique_ptr<Node> extractTree() { 
    // This seems less intuitive to me 
    return std::unique_ptr<Node>{this->root.release()}; 
} 

est-std::move() le meilleur choix?

+0

Vous devez appeler '' reset' de this-> root' après son déplacement. Tu ferais mieux de lire cette réponse aussi http://stackoverflow.com/a/20850223/555515 – neuront

+2

@neuront: Non, non. –

+0

après avoir déplacé le src contient nullptr, la réinitialisation est inutile! – paulm

Répondre

4

vous devriez aller avec la definitly première version que le second fait essentiellement le tout la première version fait avec plus de code et moins lisibilité. Philosophiquement parlant, la seconde version déplace le pointeur unique, ni plus, ni moins. alors pourquoi faire le tour de la table au lieu d'utiliser le déjà existant, plus lisible et plus idiomatique std::unique_ptr(std::unique_ptr&&)? Enfin, si votre pointeur intelligent quelque part dans le futur tiendra costume deleter, la première version s'assurera que le suppresseur se déplace également, la deuxième version ne déplace pas le suppresseur. Je peux defenitly imaginer programmeur bâtiment non-costume deleter pointeur unique sur costum-deleter unique_pointer avec l'aide release. avec les semantics de mouvement, le programme échouera à compiler.

3

Ce que vous faites est dangereux. Une fois que vous avez appelé getTree(), vous ne devez pas l'appeler une seconde fois, ce qui n'est pas clair à partir de l'interface. Vous voudrez peut-être reconsidérer votre conception (par exemple, shared_ptr pourrait faire un meilleur travail, ou simplement stocker la racine en tant que pointeur brut et prendre manuellement en charge le désallocation).

Quoi qu'il en soit, en utilisant std::move est la meilleure option des deux si vous voulez coller avec votre conception car il rend votre intention plus claire.

EDIT: Apparemment, « ne doit pas » a un sens particulier de forbideness en anglais, je ne connaissais pas. Il est bon d'appeler la fonction deux fois ou autant de fois que vous le souhaitez, mais ne retournera pas un pointeur vers un objet valide s'il est fait consécutivement.

+0

Il n'y a aucun problème à appeler 'getTree()' une seconde fois. Cela retournera juste un 'unique_ptr' nul. –

+1

Pourquoi ne pas appeler 'getTree()' deux fois? Une fois que la racine est déplacée, elle est définie sur 'nullptr', donc en bouger à nouveau vous obtenez un' nullptr', ce qui semble être un comportement très raisonnable pour un objet vide. – nwp

+0

n'est-ce pas la raison pour laquelle il vous suggère de ne pas l'appeler deux fois ... – AngryDuck