web-dev-qa-db-fra.com

Obtenir un coup de pouce :: shared_ptr pour cela

J'utilise largement boost:shared_ptr Dans mon code. En fait, la plupart des objets qui sont alloués sur le tas sont détenus par un shared_ptr. Malheureusement, cela signifie que je ne peux pas passer this dans une fonction qui prend un shared_ptr. Considérez ce code:

void bar(boost::shared_ptr<Foo> pFoo)
{
    ...
}

void Foo::someFunction()
{
    bar(this);
}

Ici, nous avons deux problèmes. Tout d'abord, cela ne se compilera pas car le constructeur T * pour shared_ptr Est explicite. Deuxièmement, si je le force à construire avec bar(boost::shared_ptr<Foo>(this)) j'aurai créé un deuxième pointeur partagé vers mon objet qui conduira finalement à une double suppression.

Cela m'amène à ma question: existe-t-il un modèle standard pour obtenir une copie du pointeur partagé existant dont vous savez qu'il existe à l'intérieur d'une méthode sur l'un de ces objets? Est-ce que l'utilisation de références intrusives compte ma seule option ici?

76
Joe Ludwig

Vous pouvez dériver de enable_shared_from_this puis vous pouvez utiliser "shared_from_this ()" au lieu de "this" pour générer un pointeur partagé vers votre propre objet.

Exemple dans le lien:

#include <boost/enable_shared_from_this.hpp>

class Y: public boost::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
}

C'est une bonne idée lorsque vous générez des threads à partir d'une fonction membre pour booster :: bind vers un shared_from_this () au lieu de cela. Cela garantira que l'objet n'est pas libéré.

102
Brian R. Bondy

Utilisez simplement un pointeur brut pour votre paramètre de fonction au lieu de shared_ptr. Le but d'un pointeur intelligent est de contrôler la durée de vie de l'objet, mais la durée de vie de l'objet est déjà garantie par les règles de portée C++: elle existera au moins aussi longtemps que la fin de votre fonction. Autrement dit, le code appelant ne peut pas supprimer l'objet avant le retour de votre fonction; ainsi la sécurité d'un pointeur "muet" est garantie, tant que vous n'essayez pas de supprimer l'objet à l'intérieur de votre fonction.

Le seul moment où vous devez passer un shared_ptr dans une fonction est lorsque vous souhaitez transmettre la propriété de l'objet à la fonction ou que la fonction doit faire une copie du pointeur.

19
Mark Ransom

boost a une solution pour ce cas d'utilisation, vérifiez enable_shared_from_this

14
David Pierre

Faites-vous vraiment des copies plus partagées de pFoo dans la barre? Si vous ne faites rien de fou à l'intérieur, faites-le:


void bar(Foo &foo)
{
    // ...
}
9
Greg Rogers

Avec C++ 11 shared_ptr et enable_shared_from_this est maintenant dans la bibliothèque standard. Ce dernier est, comme son nom l'indique, exactement pour ce cas.

http://en.cppreference.com/w/cpp/memory/shared_ptr

http://en.cppreference.com/w/cpp/memory/enable_shared_from_this

Exemple basé sur cela dans les liens ci-dessus:

struct Good: std::enable_shared_from_this<Good>{
    std::shared_ptr<Good> getptr() {
        return shared_from_this();
    }
};

utilisation:

std::shared_ptr<Good> gp1(new Good);
std::shared_ptr<Good> gp2 = gp1->getptr();
std::cout << "gp2.use_count() = " << gp2.use_count() << '\n';
5
Johan Lundberg

La fonction acceptant un pointeur souhaite effectuer l'un des deux comportements suivants:

  • Posséder l'objet transmis et le supprimer lorsqu'il sort de la portée. Dans ce cas, vous pouvez simplement accepter X * et envelopper immédiatement un scoped_ptr autour de cet objet (dans le corps de la fonction). Cela fonctionnera pour accepter "ceci" ou, en général, tout objet alloué par segment de mémoire.
  • Partagez un pointeur (ne le possédez pas) sur l'objet transmis. Dans ce cas, vous faites pas voulez utiliser un scoped_ptr du tout, car vous ne voulez pas supprimer l'objet à la fin de votre fonction. Dans ce cas, ce que vous voulez théoriquement, c'est un shared_ptr (je l'ai vu appelé un Linked_ptr ailleurs). La bibliothèque boost a ne version de shared_ptr , et cela est également recommandé dans le livre Effective C++ de Scott Meyers (point 18 de la 3e édition).

Edit: Oops J'ai mal lu la question, et je vois maintenant que cette réponse ne répond pas exactement à la question. Je Je le laisserai quand même, au cas où cela pourrait être utile pour toute personne travaillant sur un code similaire.

3
Tyler