410 votes

quelle est l'utilité de enable_shared_from_this

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.

414voto

1800 INFORMATION Points 55907

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.

257voto

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
}

36voto

mackenir Points 4271

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.

4voto

blais Points 169

Notez que l'utilisation de boost :: intrusive_ptr ne souffre pas de ce problème. C'est souvent un moyen plus pratique de contourner ce problème.

-3voto

PetrH Points 9

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.

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