J'ai couru à travers enable_shared_from_this
en lisant les exemples de Boost.Asio et après avoir lu la documentation je suis toujours perdu pour savoir comment cela devrait être correctement utilisé. Quelqu'un peut-il s'il vous plaît me donner un exemple et / ou une explication de l'utilisation de cette classe est logique.
Réponses
Trop de publicités?Il vous permet d'obtenir une valide shared_ptr
exemple d' this
, quand tout ce que vous avez est - this
. Sans elle, vous n'avez aucun moyen d'obtenir un shared_ptr
de this
, sauf si vous avez déjà eu un en tant que membre. Cet exemple de la boost documentation pour enable_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 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:
class Y: public enable_shared_from_this<Y>
{
public:
shared_ptr<Y> f()
{
return shared_ptr<Y>(this);
}
}
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
va être une partie de la nouvelle C++0x standard, de sorte que vous pouvez également l'obtenir à partir de là, ainsi que de boost.
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:
int *ip = new int;
shared_ptr<int> sp1(ip);
shared_ptr<int> sp2(ip);
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:
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'il est construit, le shared_ptr objet sp1 est propriétaire de la nouvellement allouée ressources. Le code à l'intérieur de la fonction de membre S::dangereux ne connais pas cette shared_ptr objet, de sorte que le shared_ptr objet auquel il renvoie est distincte de sp1. La copie de la nouvelle shared_ptr objet de sp2 n'aide pas; lorsque le service pack 2 est hors de portée, elle va libérer de la ressource, et une fois que le sp1 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 [6]. 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:
struct S : enable_shared_from_this<S>
{
shared_ptr<S> dangerous()
{
return shared_from_this();
}
};
int main()
{
shared_ptr<S> sp1(new S);
shared_ptr<S> sp2 = sp1->dangerous(); // not dangerous
return 0;
}
La fonction de membre S::dangereux n'est plus dangereux. Lorsque vous faites cela, gardez à l'esprit que l'objet que vous appelez shared_from_this doit être détenue par un shared_ptr objet. Cela ne fonctionne pas:
int main()
{
S *p = new S;
shared_ptr<S> sp2 = p->dangerous(); // don't do this
}
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>
exemple d' T
qui détient le"seul vrai compte de référence"pour l'instance de T
.
Ainsi, lorsque vous créez d'abord un shared_ptr<T>
sur un nouveau T*, T*'interne weak est initialisé avec un refcount 1. Le nouveau shared_ptr
essentiellement le dos sur cette weak_ptr
.
T
peut alors, dans ses méthodes, appel shared_from_this
pour obtenir une instance de l' shared_ptr<T>
qui s'adosse à la même stockée en interne de comptage de référence. De cette façon, vous avez toujours un endroit où l' T*
's réf-comte est stocké plutôt que d'avoir plusieurs shared_ptr
des instances qui ne connaissent pas les uns les autres, et chacun pense qu'ils sont l' shared_ptr
qui est en charge de la réf de comptage T
et de les supprimer lors de leur ref-compte à rebours atteint zéro.
Une autre façon est d'ajouter un weak_ptr<Y> m_stub
membre dans l' class Y
. Alors écrire:
shared_ptr<Y> Y::f()
{
return m_stub.lock();
}
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 le membre, par exemple en m_stub = shared_ptr<Y>(this)
, le son est valable même au cours d'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.