0

I have a class A that provides methods to construct instances of class B. And B holds a private reference to A and provides a constructor to set this reference.

class A { 
   public: 
     B* construct_B ();
}
class B {
  private:
    const A& private_A;
  public:
    B ( const A& my_A ): private_A (my_A) { }
}

The implementation of construct_B takes care of dynamic allocation and passing the reference to itself via this.

How do I implement this setup in such a way that I make sure that the lifetime of A is longer than B so that its reference remains valid? Notice that I don't care about all the possibilities of construct_B instead of returning a raw pointer I could return a smart pointer or similar.

One possible way of solving this could be having B instead of holding a reference to hold a smart pointer to A, and instead of dynamically allocating B in construct_B to take a static reference to B and then set it's pointer, something like

class A : 
   public std::enable_shared_from_this<A> { 
   public: 
      void setup_B ( const B& my_B ) { 
        my_B.set_A (shared_ptr_from_this() ) ;
}
class B {
  private:
    const shared_ptr<A> private_A_ptr;
  public:
    void set_A ( const shared_ptr<A> my_A ): 
        private_A_ptr (my_A) { }
}

which then could be implemented by int main () { A static_A; B static_B; A.setup_B (static_B); }

Does the shared_ptr of this last construction avoid the problem of A being deleted before B?

Reimundo Heluani
  • 918
  • 9
  • 18
  • Why don't you try it out and make some console output? But here A will be deleted only when no-one points to A anymore. – Hayt Sep 15 '16 at 14:15
  • 1
    "Does the shared_ptr of this last construction avoid the problem of A being deleted before B?' yes it does. The only caveat is that A itself must be owned by a shared_ptr otherwise shared_from_this() will be UB. – Richard Hodges Sep 15 '16 at 14:27

1 Answers1

2

shared_ptr is your answer. Something like this:

#include <memory>

struct A;

class B {
    const std::shared_ptr<A> private_A_ptr;
  public:
  B(std::shared_ptr<A> parent) : private_A_ptr(std::move(parent)) {}
};

struct A : 
std::enable_shared_from_this<A> 
{ 
  B make_b() {
    return B(shared_from_this());
  }
};

int main()
{
  // this would be invalid:  
  //A a;
  //auto b = a.make_b();

  // but this is fine

  auto pa = std::make_shared<A>();
  auto b = pa->make_b();

  // later...
  pa.reset();

  // A still exists because ownership was shared with b

}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142