Подтвердить что ты не робот

Std:: shared_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 передать сам std::shared_ptr (this) его дочернему элементу?

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

4b9b3361

Ответ 1

Существует 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() внутри конструктора или деструктора.

Ответ 2

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

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

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

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