c++shared-ptrownership-semantics

How to keep one object alive as long as another object exists?


Is there a way to prevent one particular object of being destroyed while another object still exists, without explicitly making the class of the second one to know about the first?

Here is an example:

class A { /* A creates B*/ };
class B {};

int main() {
    auto spA = std::make_shared<A>();
    auto spB = spA->getB();

    spA.reset();
    spB->DoSomething(); 
}

After spA.reset(), I would like to have at least one reference to the object pointed by spA. Or, in other words: I would like to destroy the object pointed by spA only after calling spB->DoSomething().

But, an important prerequisite is B is not allowed to "know" about A (e.g. it is not allowed to hold a pointer/reference to it).

As I understand, shared pointers provide some functionality which can help with dealing with this problem, but I am not sure which one.

EDIT:

The brief structure of A and B look as follows:

class A 
{
public:
    A() 
    { 
        m_B = B::FactoryB(); 
    }
    std::shared_ptr<B> getB()
    {
        return m_B;
    }
private:
    std::shared_ptr<B> m_B; 
};

class B 
{
public:
    static std::shared_ptr FactoryB()
    {
        return std::make_shared<B>();
    }
};

EDIT2 (MY SOLUTION):

So, using suggestion provided by @MSalters I was able to find a solution that works for me. In this case it was much simpler than expected, such that I only needed to adjust A::getB():

    std::shared_ptr<B> getB()
    {
        std::shared<B> spBAlias(this->shared_from_this(), m_B.get());
        return spBAlias;
    }

Here, instead of just returning m_B, A::getB() creates and returns a shared pointer spBAlias of type B (using alias constructor), which influences the reference counting of the A object (provided by this->shared_from_this()). So, calling spA.reset() in the main decreases uses of spA from two to one, making the call of spB->DoSomething() possible. To use shared_from_this(), A needs to inherit from std::enable_shared_from_this<A>:

class A : public std::enable_shared_from_this<A> { /* ... */ }

Solution

  • shared_ptr has something called an aliasing constructor. A shared_ptr<B> can be created from a shared_ptr<A> and a B*. The destructor of this shared_ptr<B> will delete the A object, not the B.

    In your case, your A object could itself hold a unique_ptr<B>, or even an outright B member.