std::shared_ptr of this

C++ThisShared PtrThis Pointer

C++ Problem Overview


I am currently trying to learn how to use smart pointers. However while doing some experiments I discovered the following situation for which I could not find a satifying solution:

Imagine you have an object of class A being parent of an object of class B (the child), but both should know each other:

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

The question is how can an object of class A pass a std::shared_ptr of itself (this) to its child?

There are solutions for Boost shared pointers (Getting a boost::shared_ptr for this), but how to handle this using the std:: smart pointers?

C++ Solutions


Solution 1 - C++

There is std::enable_shared_from_this just for this purpose. You inherit from it and you can call .shared_from_this() from inside the class. Also, you are creating circular dependencies here that can lead to resource leaks. That can be resolved with the use of std::weak_ptr. So your code might look like this (assuming children rely on existence of parent and not the other way around):

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

Note however, that calling .shared_from_this() requires that this is owned by std::shared_ptr at the point of call. This means that you cannot create such object on stack anymore, and generally cannot call .shared_from_this() from within a constructor or destructor.

Solution 2 - C++

You have several problems in you design, that seem to stem from you misunderstanding of smart pointers.

Smart pointers are used to declare ownership. You are breaking this by declaring that both the parents owns all children, but also that each child own it's parent. Both can't be true.

Also, you are returning a weak pointer in getChild(). By doing so, you are declaring that the caller shouldn't care about the ownership. Now this can be very limiting, but also by doing so, you must make sure that the child in question won't get destroyed while any weak pointers are still held, if you would use a smart pointer, it would get sorted out by itself.

And the final thing. Usually, when you are accepting new entities, you should usually accept raw pointers. Smart pointer can have their own meaning for swapping children between parents, but for general usage, you should accept raw pointers.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionIcarusView Question on Stackoverflow
Solution 1 - C++yuri kilochekView Answer on Stackoverflow
Solution 2 - C++Šimon TóthView Answer on Stackoverflow