129 votes

std::shared_ptr de ceci

J'essaie actuellement d'apprendre à utiliser les 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 qu'un objet de classe A soit le parent d'un objet de classe B (l'enfant), mais que les deux doivent 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 la classe A peut transmettre 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 ?

205voto

yuri kilochek Points 3643

Il y a std::enable_shared_from_this juste à cette fin. Vous en héritez et vous pouvez appeler .shared_from_this() depuis l'intérieur de la classe. En outre, vous créez ici des dépendances circulaires qui peuvent entraîner des fuites de ressources. Cela peut être résolu par l'utilisation de std::weak_ptr . Votre code pourrait donc ressembler à ceci (en supposant que les enfants dépendent de l'existence du 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 qu'appeler .shared_from_this() exige que this est détenu par std::shared_ptr au moment de l'appel. Cela signifie qu'il n'est plus possible de créer un tel objet sur la pile, et que la fonction généralement ne peut pas appeler .shared_from_this() à l'intérieur d'un constructeur ou d'un destructeur.

12voto

Let_Me_Be Points 16797

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 enfreignez cette règle en déclarant que les parents possèdent tous les enfants, mais aussi que chaque enfant possède son parent. Les deux ne peuvent pas être vrais.

De plus, vous retournez un pointeur faible dans le fichier getChild() . En faisant cela, vous déclarez que l'appelant ne doit pas se soucier de la propriété. Maintenant, cela peut être très contraignant, mais aussi en faisant cela, vous devez vous assurer que l'enfant en question ne sera pas détruit alors que des pointeurs faibles sont encore détenus, si vous utilisez un pointeur intelligent, cela sera réglé par lui-même.

Et la dernière chose. Habituellement, lorsque vous acceptez de nouvelles entités, vous devriez accepter des pointeurs bruts. Les pointeurs intelligents peuvent avoir leur propre signification pour échanger des enfants entre parents, mais pour un usage général, vous devriez accepter les pointeurs bruts.

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