std:: общий ptr этого


в настоящее время я пытаюсь научиться использовать интеллектуальные указатели. Однако, проводя некоторые эксперименты, я обнаружил следующую ситуацию, для которой я не мог найти удовлетворительное решение:

представьте, что у вас есть объект класса A, являющийся родителем объекта класса B (ребенок), но оба должны знать друг друга:

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

вопрос в том, как объект класса A может пройти a std::shared_ptr само по себе (this) своему ребенку?

есть решения для Повышение общих указателей (получение boost::shared_ptr на this), но как справиться с этим с помощью std:: умные указатели?

2 64

2 ответа:

здесь std::enable_shared_from_this только для этой цели. Вы наследуете от него, и вы можете позвонить .shared_from_this() внутри класса. Также здесь создаются циклические зависимости, которые могут привести к утечкам ресурсов. Это можно решить с помощью std::weak_ptr. Таким образом, ваш код может выглядеть так (предполагая, что дети полагаются на существование родителя, а не наоборот):

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

обратите внимание, однако, что вызов .shared_from_this() требует, чтобы this принадлежит std::shared_ptr в точке вызова. Это означает, что вы больше не можете создать такой объект в стеке, и вообще не могу назвать .shared_from_this() из конструктора или деструктора.

у вас есть несколько проблем в вашем дизайне, которые, похоже, вытекают из вашего непонимания умных указателей.

интеллектуальные указатели используются для объявления собственности. Вы нарушаете это, заявляя, что оба родителя владеют всеми детьми, но также и что каждый ребенок владеет своим родителем. И то и другое не может быть правдой.

кроме того, вы возвращаете слабый указатель в getChild(). Поступая таким образом, вы объявляете, что абонент не должен заботиться о собственности. Теперь это может быть очень ограничивающим, но также, делая это, вы должны убедиться, что ребенок, о котором идет речь, не будет уничтожен, пока все слабые указатели все еще удерживаются, если вы будете использовать умный указатель, он будет отсортирован сам по себе.

и последнее. Обычно, когда вы принимаете новые сущности, вы обычно должны принимать необработанные указатели. Умный указатель может иметь собственное значение для обмена детьми между родителями, но для общего использования, вы должны принимать сырые указатели.