Quelle est l'utilité de "permettre partagé à partir de cette"?
j'ai couru à travers enable_shared_from_this
en lisant le Boost.Asio exemples et après avoir lu la documentation je suis encore perdu pour la façon 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.
6 réponses
il vous permet d'obtenir une instance valide shared_ptr
à this
, quand tout ce que vous avez est this
. Sans elle , vous n'auriez aucun moyen d'obtenir un shared_ptr
à this
, sauf si vous en aviez déjà un comme membre. Cet exemple tiré de la documentation boost pour enabl_shared_from_this :
class Y: public enable_shared_from_this<Y>
{
public:
shared_ptr<Y> f()
{
return shared_from_this();
}
}
int main()
{
shared_ptr<Y> p(new Y);
shared_ptr<Y> q = p->f();
assert(p == q);
assert(!(p < q || q < p)); // p and q must share ownership
}
la méthode f() renvoie une shared_ptr
valide , même si elle n'a pas d'instance de membre. Notez que vous ne pouvez pas tout simplement ceci:
class Y: public enable_shared_from_this<Y>
{
public:
shared_ptr<Y> f()
{
return shared_ptr<Y>(this);
}
}
le pointeur partagé que ce retour aura un compte de référence différent de celui" correct", et l'un d'eux finira par perdre et tenir une référence pendante lorsque l'objet est supprimé.
enable_shared_from_this
fait désormais partie de la norme C++ 11. Vous pouvez également l'obtenir à partir de là, ainsi que de boost.
de L'article du Dr Dobbs sur les points faibles, je pense que cet exemple est plus facile à comprendre (source: http://drdobbs.com/cpp/184402026 ):
...un code comme celui-ci ne fonctionnera pas correctement:
int *ip = new int;
shared_ptr<int> sp1(ip);
shared_ptr<int> sp2(ip);
aucun des deux shared_ptr
objets ne connaît l'autre, donc les deux vont essayer de libérer la ressource quand ils sont détruits. Qui conduit généralement à des problèmes.
fonction membre a besoin d'un shared_ptr
objet propriétaire de l'objet qu'on l'appelle, il ne peut pas créer un objet à la volée:
struct S
{
shared_ptr<S> dangerous()
{
return shared_ptr<S>(this); // don't do this!
}
};
int main()
{
shared_ptr<S> sp1(new S);
shared_ptr<S> sp2 = sp1->dangerous();
return 0;
}
Ce code a le même problème que l'exemple précédent, bien que sous une forme plus subtile. Lorsqu'elle est construite, l'objet shared_pt
R sp1
est propriétaire de la ressource nouvellement attribuée. Le code à l'intérieur de la fonction membre S::dangerous
ne sait pas à propos de cet "objet 151940920", donc l'objet shared_ptr
qu'il le retour est à distinguer de la sp1
. Copier le nouvel objet shared_ptr
vers sp2
n'aide pas; quand sp2
sort de la portée, il libère la ressource, et quand sp1
sort de la portée, il libère la ressource à nouveau.
La manière d'éviter ce problème est d'utiliser le modèle de classe enable_shared_from_this
. Le template prend un argument template type, qui est le nom de la classe qui définit la ressource gérée. Cette classe doit, à son tour,,
struct S : enable_shared_from_this<S>
{
shared_ptr<S> not_dangerous()
{
return shared_from_this();
}
};
int main()
{
shared_ptr<S> sp1(new S);
shared_ptr<S> sp2 = sp1->not_dangerous();
return 0;
}
Lorsque vous faites cela, gardez à l'esprit que l'objet sur lequel vous appelez shared_from_this
doit être possédé par un shared_ptr
objet. Cela ne marchera pas:
int main()
{
S *p = new S;
shared_ptr<S> sp2 = p->not_dangerous(); // don't do this
}
Voici mon explication, du point de vue des écrous et des boulons (la réponse du haut n'a pas "cliqué" avec moi). * Notez que ceci est le résultat d'une enquête sur la source de shared_ptr et enable_shared_from_this fourni avec Visual Studio 2012. Peut-être que d'autres compilateurs implémentent enabl_shared_f_this différemment...*
enable_shared_from_this<T>
ajoute une instance privée weak_ptr<T>
à T
qui détient le " un véritable compte de référence pour le instance de T
.
Ainsi, lorsque vous créez pour la première fois un shared_ptr<T>
sur un nouveau T*, que le fichier weak_ptr interne de T*est initialisé avec un refcount de 1. Le nouveau shared_ptr
revient en gros sur ce weak_ptr
.
T
peut alors, dans ses méthodes, appeler shared_from_this
pour obtenir une instance de shared_ptr<T>
que retourne sur le même nombre de référence stocké en interne . De cette façon, vous avez toujours une place où T*
's ref-count est stocké plutôt que d'avoir plusieurs shared_ptr
instances qui ne savent pas l'un de l'autre, et chacun pense qu'ils sont le shared_ptr
qui est en charge de la ref-counting T
et de le supprimer lorsque leur ref-count atteint zéro.
Notez que l'utilisation d'un boost::intrusive_ptr ne souffre pas de ce problème. C'est souvent une façon plus pratique de contourner cette question.
c'est exactement la même chose en c++11 et plus tard: c'est pour permettre la possibilité de retourner this
comme pointeur partagé puisque this
vous donne un pointeur brut.
en d'autres termes, il vous permet de tourner le code comme ceci
class Node {
public:
Node* getParent const() {
if (m_parent) {
return m_parent;
} else {
return this;
}
}
private:
Node * m_parent = nullptr;
};
dans ceci:
class Node : std::enable_shared_from_this<Node> {
public:
std::shared_ptr<Node> getParent const() {
std::shared_ptr<Node> parent = m_parent.lock();
if (parent) {
return parent;
} else {
return shared_from_this();
}
}
private:
std::weak_ptr<Node> m_parent;
};
une autre façon consiste à ajouter un weak_ptr<Y> m_stub
dans le class Y
. Alors écrivez:
shared_ptr<Y> Y::f()
{
return m_stub.lock();
}
utile lorsque vous ne pouvez pas changer la classe dont vous dérivez (par exemple étendre la bibliothèque d'autres personnes). N'oubliez pas d'initialiser le membre, par exemple par m_stub = shared_ptr<Y>(this)
, son est valide même pendant un constructeur.
S'il y a plus de talons comme celui-ci dans la hiérarchie des héritages, cela n'empêchera pas la destruction de l'objet.
Edit: comme l'utilisateur nobar l'a correctement souligné, le code détruirait L'objet Y lorsque l'affectation est terminée et les variables temporaires sont détruites. Donc ma réponse est incorrecte.