46 votes

Passer unique_ptr aux fonctions

Je suis en train de "moderniser" le code existant.

  • J'ai une classe qui dispose actuellement d'une variable membre "de l'Appareil* device_".
  • Il utilise à nouveau pour créer une instance dans certains code d'initialisation et a un "supprimer device_" dans le destructory.
  • Les fonctions de membres de cette classe appel à de nombreuses autres fonctions qui prennent un Périphérique* en tant que paramètre.

Cela fonctionne bien, mais pour "moderniser" mon code je pensais que je devais changer la variable est définie comme "std::unique_ptr<Device> device_" et de supprimer l'appel explicite à supprimer, ce qui rend le code plus sûr et meilleur.

Ma question est la suivante -

  • Comment dois-je passe ensuite l' appareil_ variable pour toutes les fonctions qui ont besoin de lui comme un paramater?

Je peux appeler .get pour obtenir le pointeur brut dans chaque appel de fonction. Mais qui semble laid et déchets-unes des raisons pour utiliser un unique_ptr en premier lieu.

Ou je peux changer chaque fonction, de sorte qu'au lieu de prendre un paramètre de type "Périphérique*" il faut maintenant une paramater de type "std::unique_ptr& ". Qui (pour moi) un peu dissimule les prototypes de fonction, et les rend difficile à lire.

Quelles sont les meilleures pratiques pour cela? Ai-je oublié d'autres options?

44voto

Matthieu M. Points 101624

En Moderne style C++, il y a deux concepts clés:

  • La propriété
  • La nullité

La propriété est sur le propriétaire d'un objet/ressource (dans le cas, une instance de Device). Les différents std::unique_ptr, boost::scoped_ptr ou std::shared_ptr sont au sujet de la propriété.

La nullité est beaucoup plus simple: il exprime l'existence ou non d'un objet donné peut être null, et ne se soucie pas d'autre chose, et certainement pas au sujet de la propriété!


Vous étiez à droite pour déplacer la mise en œuvre de votre classe vers unique_ptr (en général), mais vous voudrez peut-être un pointeur intelligent avec copie en profondeur sémantique si votre objectif est de mettre en œuvre un PIMPL.

Cela indique clairement que votre classe est-elle la seule responsable de ce morceau de mémoire et soigneusement traite avec toutes les différentes manières de mémoire pourraient avoir fui le contraire.


D'autre part, la plupart des utilisateurs des ressources pourraient soins de moins sur sa propriété.

Tant qu'une fonction n'a pas de conserver une référence à un objet (le stocker dans une carte ou quelque chose), alors tout ce qui compte, c'est que la durée de vie de l'objet dépasse la durée de l'appel de la fonction.

Ainsi, le choix de la façon de passer le paramètre dépend de son éventuelle Nullité:

  • Jamais null ? Passer une référence
  • Possiblité null ? Passer un pointeur, un simple pointeur nu ou un pointeur-comme la classe (avec un piège à null par exemple)

14voto

juanchopanza Points 115680

Ça dépend vraiment. Si une fonction doit prendre possession du unique_ptr, alors il est la signature devrait prendre unique_ptr<Device> bv valeur et l'appelant doit std::move le pointeur. Si la propriété n'est pas un problème, alors je conserverais la signature du pointeur brut et le transmettrais à un_ptr unique en utilisant get() . Ce n'est pas moche si la fonction en question ne prend pas la propriété.

7voto

mkaes Points 6867

Je voudrais utiliser std::unique_ptr const& . L'utilisation d'une référence non const donnera à la fonction appelée la possibilité de réinitialiser votre pointeur.
Je pense que c’est un bon moyen d’exprimer que votre fonction appelée peut utiliser le pointeur, mais rien d’autre.
Donc, pour moi, cela rendra l'interface plus facile à lire. Je sais que je n'ai pas besoin de bricoler avec le pointeur qui m'a été transmis.

2voto

James Kanze Points 96599

La meilleure pratique est probablement de ne pas utiliser std::unique_ptr dans ce cas, bien que cela dépend. (En général, vous ne devriez pas avoir plus d'un raw pointeur vers un objet alloué dynamiquement dans une classe. Bien que ce dépend aussi.) La seule chose que vous ne voulez pas faire dans ce cas est de passage autour de std::unique_ptr (et comme vous l'avez remarqué, std::unique_ptr<> const& est un peu lourd et abrutissant). Si ce est le seul allouée dynamiquement pointeur sur l'objet, je venais de bâton avec le pointeur brut, et l' delete dans le destructeur. Si il y a plusieurs de ces pointeurs, je voudrais examiner les reléguant à chacun d'eux à un séparée de la classe de base (où ils peuvent encore être cru pointeurs).

1voto

J.N. Points 4858

Qui peut ne pas être réalisable pour vous, mais un remplacement de toutes les occurrences de Device* par const unique_ptr<Device>& est un bon début.

Manifestement, vous ne pouvez pas copier unique_ptrs et vous ne voulez pas vous déplacer. Remplacer par un renvoi à l' unique_ptr permet au corps de fonctions existantes corps de continuer à travailler.

Maintenant, il y a un piège, vous devez passer par const & pour prévenir les fonctions appelées de faire unique_ptr.reset() ou unique_ptr().release(). Notez que cela passe modifiable pointeur vers l'appareil. Avec cette solution, vous n'avez pas de moyen facile de passer un pointeur ou une référence à un const Device.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X