Quelle est l'utilité de " enable_shared_from_this`?
J'ai couru à travers enable_shared_from_this
lors de la lecture de la Stimuler.Asio exemples et après la lecture de la documentation, je suis encore perdu pour la manière dont cela devrait être correctement utilisé. Quelqu'un peut-il me donner un exemple et/ou explication lors de l'utilisation de cette classe de sens.
Vous devez vous connecter pour publier un commentaire.
Il vous permet d'obtenir une valide
shared_ptr
instance dethis
, quand tout ce que vous avez estthis
. Sans elle, vous n'avez aucun moyen d'obtenir unshared_ptr
àthis
, sauf si vous avez déjà eu un en tant que membre. Cet exemple de la stimuler la documentation pour enable_shared_from_this:La méthode f() renvoie un valide
shared_ptr
, même si elle n'avait pas de membre de l'instance. Notez que vous ne pouvez pas simplement faire ceci:Le pointeur partagé que cette retourné sera différent de comptage de référence de la "bonne", et l'un d'entre eux finissent par perdre et la tenue d'une balançant de référence lorsque l'objet est supprimé.
enable_shared_from_this
est devenue une partie de C++ 11. Vous pouvez également l'obtenir à partir de là, ainsi que de boost.std::shared_ptr
constructeur sur un pointeur brut si il hérite destd::enable_shared_from_this
. je ne sais pas si du coup de pouce de la sémantique ont été mis à jour à l'appui de cette.std::shared_ptr
pour un objet qui est déjà géré par un autrestd::shared_ptr
ne sera pas consulter l'stockée en interne de référence faible et par conséquent conduit à un comportement indéfini." (en.cppreference.com/w/cpp/memory/enable_shared_from_this)shared_ptr<Y> q = p
?q
et vous avez besoin d'unp
de l'intérieur de la classe.std::make_shared<T>
.de Dr Dobbs article sur des pointeurs faibles, je pense que cet exemple est plus facile à comprendre (source: http://drdobbs.com/cpp/184402026):
...code comme celui-ci ne fonctionne pas correctement:
Aucun des deux
shared_ptr
objets connaît les autres, de sorte que les deux vont essayer de libérer la ressource lorsqu'ils sont détruits. Qui conduit généralement à des problèmes.De même, si un membre de la fonction a besoin d'un
shared_ptr
objet qui est propriétaire de l'objet auquel il est appelé, il ne peut pas créer un objet à la volée:Ce code a le même problème que l'exemple précédent, bien que sous une forme plus subtile. Lorsqu'il est construit, le
shared_pt
objet rsp1
propriétaire de la nouvellement allouée ressources. Le code à l'intérieur de la fonction de membre deS::dangerous
ne connais pas cetteshared_ptr
objet, de sorte que leshared_ptr
objet auquel il renvoie est distincte desp1
. La copie de la nouvelleshared_ptr
objet desp2
n'aide pas; quandsp2
est hors de portée, elle va libérer la ressource, et quandsp1
est hors de portée, elle va libérer la ressource.La façon d'éviter ce problème est d'utiliser le modèle de classe
enable_shared_from_this
. Le modèle est un modèle de type d'argument, qui est le nom de la classe qui définit la ressource gérée. Cette classe doit, à son tour, être dérivé du public à partir de ce modèle, comme ceci:Lorsque vous faites cela, gardez à l'esprit que l'objet sur lequel vous appelez
shared_from_this
doit être possédé par unshared_ptr
objet. Cela ne fonctionne pas:shared_ptr<S> sp1(new S);
il peut être préférable d'utilisershared_ptr<S> sp1 = make_shared<S>();
, voir par exemple stackoverflow.com/questions/18301511/...shared_ptr<S> sp2 = p->not_dangerous();
parce que le piège est ici que vous doit créer un shared_ptr la normale avant de vous appelershared_from_this()
la première fois! C'est vraiment facile de se tromper! Avant le C++17 c'est AC pour appelershared_from_this()
avant exactement un shared_ptr a été créé de façon normale:auto sptr = std::make_shared<S>();
oushared_ptr<S> sptr(new S());
. Heureusement, à partir de C++à partir de 17 de le faire va les jeter.S* s = new S(); shared_ptr<S> ptr = s->not_dangerous();
<-- Il est permis d'appeler shared_from_this seulement sur un objet partagé, c'est à dire sur un objet géré par std::shared_ptr<T>. Sinon le comportement est indéfini (jusqu'en C++17)std::bad_weak_ptr est lancé (par le shared_ptr constructeur par défaut construit weak_this) (depuis C++17).. Donc, la réalité est qu'il doit être appeléalways_dangerous()
, parce que vous avez besoin de la connaissance de si elle a déjà été partagé ou pas.Voici mon explication, à partir d'une noix et des boulons de point de vue (en haut de réponse n'a pas de "clic" avec moi). *Notez que ceci est le résultat d'une enquête sur la source de shared_ptr et enable_shared_from_this qui est fourni avec Visual Studio 2012. Peut-être d'autres compilateurs de mettre en œuvre enable_shared_from_this différemment...*
enable_shared_from_this<T>
ajoute un privéweak_ptr<T>
instance deT
qui détient le "un vrai compte de référence " pour l'instance deT
.Ainsi, lorsque vous créez d'abord un
shared_ptr<T>
sur un nouveau T*, T*'s internes weak est initialisé avec un refcount 1. La nouvelleshared_ptr
essentiellement le dos sur cetteweak_ptr
.T
peut alors, dans ses méthodes, appelshared_from_this
pour obtenir une instance deshared_ptr<T>
que dos sur le même stockée en interne nombre de références. De cette façon, vous avez toujours un endroit oùT*
's réf-comte est stocké plutôt que d'avoir plusieursshared_ptr
instances qui ne connaissent pas les uns les autres, et chacun pense qu'ils sont lesshared_ptr
qui est en charge de la réf de comptageT
et de les supprimer lors de leur ref-compte à rebours atteint zéro.So, when you first create...
parce que c'est un condition (comme vous le dites l'weak n'est pas initialisé jusqu'à ce que vous passer les objets pointeur dans un shared_ptr ctor!) et cette exigence est là où les choses peuvent aller mal si vous n'êtes pas prudent. Si vous créez pas de shared_ptr avant d'appelershared_from_this
vous obtenez UB - de même, si vous créez plus d'un shared_ptr vous obtenez UB trop. Vous avez en quelque sorte assurez-vous de créer un shared_ptr exactement une fois.enable_shared_from_this
est fragile pour commencer, car le point est d'être en mesure d'obtenir unshared_ptr<T>
à partir d'unT*
, mais en réalité, lorsque vous recevez un pointeurT* t
il n'est généralement pas sûr de supposer quoi que ce soit à ce sujet déjà partagé ou non, et faire le mal deviner UB.Noter que l'utilisation d'un boost::intrusive_ptr ne souffre pas de ce problème.
C'est souvent un moyen plus pratique d'obtenir autour de cette question.
enable_shared_from_this
vous permet de travailler avec une API qui accepte expressémentshared_ptr<>
. À mon avis, une telle API est généralement de de Faire le Mal (comme il est préférable de laisser quelque chose de plus élevé dans la pile propre de la mémoire), mais si vous êtes obligé de travailler avec une API, c'est une bonne option.C'est exactement la même chose en c++11 et plus tard: C'est pour activer la possibilité de retourner
this
comme un pointeur partagé depuisthis
vous donne un pointeur brut.en d'autres termes, il vous permet de transformer un code comme ceci
dans cette:
shared_ptr
. Vous souhaiterez peut-être modifier l'interface pour s'assurer qu'il est bien le cas.std::shared_ptr<Node> getParent const()
, je l'aurais fait normalement exposer commeNodePtr getParent const()
à la place. Si vous avez absolument besoin d'accéder à l'intérieur pointeur brut (meilleur exemple: gérer une bibliothèque en C), il n'y astd::shared_ptr<T>::get
pour que, qui, je déteste les mentionner parce que j'ai ce pointeur brut accesseur utilisé trop de fois pour les mauvaises raisons.Une autre façon est d'ajouter un
weak_ptr<Y> m_stub
membre dans leclass Y
. Alors écrire:Utile lorsque vous ne pouvez pas modifier la classe dérivant de l' (par exemple, l'extension des autres personnes de la bibliothèque). Ne pas oublier d'initialiser les membres, par exemple par
m_stub = shared_ptr<Y>(this)
, son est valable même pendant un constructeur.C'est OK si il y a plus de talons comme celui-ci dans la hiérarchie d'héritage, il ne pourra pas empêcher la destruction de l'objet.
Edit: Comme souligné à juste titre par l'utilisateur nobar, le code serait détruire la Y de l'objet lorsque la mission est terminée et les variables temporaires sont détruits. Donc ma réponse est incorrecte.
shared_ptr<>
qui ne supprime pas ses pointee, c'est exagéré. Vous pouvez simplement direreturn shared_ptr<Y>(this, no_op_deleter);
oùno_op_deleter
est une fonction unaire objet la prise deY*
et de ne rien faire.m_stub = shared_ptr<Y>(this)
construisent et immédiatement détruire temporaire shared_ptr à partir de ce. Lorsque cette instruction est terminée,this
seront supprimées et toutes les références ultérieures sera bancale.enable_shared_from_this
, elle garde uneweak_ptr
de lui-même (remplie par le ctor), retourné comme unshared_ptr
lorsque vous appelezshared_from_this
. En d'autres mots, vous êtes en reproduisant ceenable_shared_from_this
offre déjà.