Search code examples
c++shared-ptrfriend

enable_shared_from_this for friend class


I've got a class with a private ctor only constructible by friend classes using a create method:

class B {
    friend class A;
private:
    B(A* parent) { m_parent = parent; };

    A* m_parent;
};

class A {
public:
    A* createB() { return new B( this ); };
};

I want createB to instead return a shared_ptr to B. I'm currently solving it this way:

std::shared_ptr<B>
A::createB( A* parent )
{
    return std::shared_ptr<B>( new B( this ) );
}

But since there is std::enable_shared_from_this for inherited classes where my solution is declared as bad style I wanted to ask for a better solution.

Thanks.


Solution

  • The only scenario that I can see where enable_shared_from_this might come into play in your example is if B::m_parent was of type std::shared_ptr<A> instead of A*.

    #include <memory>
    class B {
        friend class A;
    private:
        B(std::shared_ptr<A> && parent) : m_parent(std::move(parent)) {}
    
        std::shared_ptr<A> m_parent;
    };
    

    In this case, createB must pass a shared_ptr<A> but you can't simply use shared_ptr<A>(this). This would cause this to be deleted when the shared_ptr was destroyed, but you didn't allocate this yourself. It's extremely improbable that this what you want to do. For example, if this is managed by an existing shared_ptr<A> then you will have two different shared_ptr<A> that don't know of each other, they will both eventually try to delete the same instance. Using enable_shared_from_this let's you get a copy of the actual shared_ptr<A> that manages this such that they are aware of each other (they share a reference counter).

    class A : std::enable_shared_from_this<A> {
    public:
        std::shared_ptr<B> createB() { 
            return std::shared_ptr<B>(new B(shared_from_this()));
        };
    };
    

    This can only work if there already exists a shared_ptr<A> to copy. For example, this would be a valid use of A::createB.

    int main()
    {
        auto my_A = std::make_shared<A>();
        auto my_B = my_A->createB();
        return 0;
    }
    

    This is not a valid use of A::createB. You will get an std::bad_weak_ptr exception.

    int main()
    {
        A my_A;
        auto my_B = my_A.createB();
        return 0;
    }
    

    Note that in the line return std::shared_ptr<B>(new B(shared_from_this())); I did not use std::make_shared<B> like I had suggested earlier. std::make_shared and non-public constructors are not compatible, you need a workaround that isn't part of your original question. See this question for more information on that.