Question

Je couru à travers enable_shared_from_this en lisant les exemples Boost.Asio et après avoir lu la documentation que je suis encore perdu de la façon dont cela devrait être utilisé correctement. Quelqu'un peut-il s'il vous plaît me donner un exemple et / ou explication et lors de l'utilisation de cette classe est logique.

Était-ce utile?

La solution

Il vous permet d'obtenir une instance de shared_ptr valide pour this, quand tout ce que vous avez est this. Sans elle, vous auriez aucun moyen d'obtenir un shared_ptr à this, à moins que vous aviez déjà un en tant que membre. Cet exemple de la documentation boost 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 () retourne un shared_ptr valable, même si elle avait pas d'instance de membre. Notez que vous ne pouvez pas faire 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 du « bon » l'un, et l'un d'entre eux finissent par perdre et la tenue d'une référence boiteuse lorsque l'objet est supprimé.

enable_shared_from_this fait partie de la norme 11 C ++. Vous pouvez également l'obtenir à partir de là, ainsi que de stimuler.

Autres conseils

de l'article Dr Dobbs sur les pointeurs faibles, je pense que cet exemple est plus facile à comprendre (source: http: // drdobbs .com / cpp / 184402026 ):

... code comme cela ne fonctionne pas correctement:

int *ip = new int;
shared_ptr<int> sp1(ip);
shared_ptr<int> sp2(ip);

Aucune des deux objets shared_ptr connaît de l'autre, de sorte que les deux vont essayer de libérer la ressource quand ils sont détruits. Cela conduit généralement à des problèmes.

De même, si une fonction membre a besoin d'un objet shared_ptr qui est propriétaire de l'objet qu'il est appelé à, il peut non seulement 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. Quand il est construit, l'objet shared_ptr sp1 est propriétaire de la ressource nouvellement allouée. Le code dans la fonction membre S::dangerous ne connaît pas cet objet shared_ptr, de sorte que l'objet shared_ptr qu'il retourne est distinct de sp1. Copie du nouvel objet shared_ptr à sp2 ne contribue pas; quand sp2 est hors de portée, il libérera la ressource, et quand sp1 est hors de portée, il publiera à nouveau 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 prend un argument de type de modèle, qui est le nom de la classe qui définit la ressource gérée. Cette classe doit, à son tour, être dérivé publiquement à partir du modèle; comme ceci:

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;
}

Quand vous faites cela, gardez à l'esprit que l'objet sur lequel vous appelez shared_from_this doit appartenir à un objet shared_ptr. Cela ne fonctionnera pas:

int main()
{
   S *p = new S;
   shared_ptr<S> sp2 = p->not_dangerous();     // don't do this
}

Voici mon explication, d'un point de vue Boulonnerie (top réponse n'a pas « 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 vient avec Visual Studio 2012. Peut-être que d'autres compilateurs différemment enable_shared_from_this ... mettre en œuvre *

enable_shared_from_this<T> ajoute une instance de weak_ptr<T> privé à T qui détient le une vraie référence count pour l'instance de T.

Alors, lorsque vous créez un shared_ptr<T> sur un nouveau T *, que weak_ptr interne de T * s'initialisé avec un refcount 1. La nouvelle shared_ptr soutient essentiellement sur ce weak_ptr.

T peut alors, dans ses méthodes, appeler shared_from_this pour obtenir une instance de shared_ptr<T> que dos sur le même nombre de référence mémorisé en interne . De cette façon, vous avez toujours un endroit où ref-comte de T* est stocké plutôt que d'avoir plusieurs instances de shared_ptr qui ne connaissent pas les uns les autres, et chacun pense qu'ils sont les shared_ptr qui est en charge de T ref-comptage et la suppression lorsque leur ref-compteur atteint zéro.

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

Il est exactement la même en c ++ 11 et plus tard. Il est de permettre la possibilité de revenir this comme pointeur partagé depuis this vous donne un pointeur brut

en d'autres termes, il vous permet d'activer 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 est d'ajouter un membre de weak_ptr<Y> m_stub dans le class Y. Ensuite, écrivez:

shared_ptr<Y> Y::f()
{
    return m_stub.lock();
}

utile lorsque vous ne pouvez pas changer la classe que vous dérivez de (par exemple étendre la bibliothèque d'autres personnes). Ne pas oublier d'initialiser le membre, par exemple par m_stub = shared_ptr<Y>(this), son est valide même au cours d'un constructeur.

Il est OK s'il y a plus de talons comme celui-ci dans la hiérarchie d'héritage, il ne sera pas empêcher la destruction de l'objet.

Modifier Comme correctement souligné Nobar utilisateur, le code de détruire un objet Y lorsque l'affectation est terminée et les variables temporaires sont détruits. Par conséquent, ma réponse est incorrecte.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top