web-dev-qa-db-fra.com

std :: shared_ptr de ceci

J'essaie actuellement d'apprendre à utiliser des pointeurs intelligents. Cependant, en faisant quelques expériences, j'ai découvert la situation suivante pour laquelle je n'ai pas pu trouver de solution satisfaisante:

Imaginez que vous ayez un objet de classe A comme parent d'un objet de classe B (l'enfant), mais les deux devraient se connaître:

class A;
class B;

class A
{
public:
    void addChild(std::shared_ptr<B> child)
    {
        children->Push_back(child);

        // How to do pass the pointer correctly?
        // child->setParent(this);  // wrong
        //                  ^^^^
    }

private:        
    std::list<std::shared_ptr<B>> children;
};

class B
{
public:
    setParent(std::shared_ptr<A> parent)
    {
        this->parent = parent;
    };

private:
    std::shared_ptr<A> parent;
};

La question est de savoir comment un objet de classe A peut passer un std::shared_ptr de lui-même (this) à son enfant?

Il existe des solutions pour les pointeurs partagés Boost ( Obtenir un boost::shared_ptr pour this ), mais comment gérer cela en utilisant le std:: des pointeurs intelligents?

77
Icarus

Il y a std::enable_shared_from_this juste à cet effet. Vous en héritez et vous pouvez appeler .shared_from_this() depuis l'intérieur de la classe. Vous créez également des dépendances circulaires ici qui peuvent entraîner des fuites de ressources. Cela peut être résolu en utilisant std::weak_ptr . Ainsi, votre code pourrait ressembler à ceci (en supposant que les enfants dépendent de l'existence d'un parent et non l'inverse):

class A;
class B;

class A
    : public std::enable_shared_from_this<A>
{
public:
    void addChild(std::shared_ptr<B> child)
    {
        children.Push_back(child);

        // like this
        child->setParent(shared_from_this());  // ok
        //               ^^^^^^^^^^^^^^^^^^
    }

private:     
    // note weak_ptr   
    std::list<std::weak_ptr<B>> children;
    //             ^^^^^^^^
};

class B
{
public:
    void setParent(std::shared_ptr<A> parent)
    {
        this->parent = parent;
    }

private:
    std::shared_ptr<A> parent;
};

Notez cependant que pour appeler .shared_from_this(), il faut que this soit la propriété de std::shared_ptr Au point d'appel. Cela signifie que vous ne pouvez plus créer un tel objet sur la pile et généralement ne peut pas appeler .shared_from_this() depuis un constructeur ou destructeur.

142
yuri kilochek

Vous avez plusieurs problèmes dans votre conception, qui semblent provenir de votre mauvaise compréhension des pointeurs intelligents.

Les pointeurs intelligents sont utilisés pour déclarer la propriété. Vous brisez cela en déclarant que les deux parents possèdent tous les enfants, mais aussi que chaque enfant possède son parent. Les deux ne peuvent pas être vrais.

En outre, vous renvoyez un pointeur faible dans getChild(). Ce faisant, vous déclarez que l'appelant ne devrait pas se soucier de la propriété. Maintenant, cela peut être très limitant, mais en faisant cela, vous devez vous assurer que l'enfant en question ne sera pas détruit pendant que des pointeurs faibles sont toujours détenus, si vous utilisiez un pointeur intelligent, il serait trié par lui-même .

Et la dernière chose. Habituellement, lorsque vous acceptez de nouvelles entités, vous devez généralement accepter des pointeurs bruts. Le pointeur intelligent peut avoir sa propre signification pour échanger des enfants entre les parents, mais pour une utilisation générale, vous devez accepter les pointeurs bruts.

7
Let_Me_Be