-2

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.

1 Answers1

1

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.

Community
  • 1
  • 1
François Andrieux
  • 28,148
  • 6
  • 56
  • 87