0

(C++) I find it a bit troublesome to managing elegantly memory in the following scenario:

I have a class named A, that has a member of class B. class B has pointer member to class C :

class C{}

class B{
 C* c;
}

class A{
 B b;
}

in class A's constructor, I initialized class B by passing it a pointer to object of class C I just created.

now, in the destructor of A, I want to free the object of class C I passed to B.

all of the options I know to do that just look for me not very elegant:

make C public in B so I can just do: "delete(b.c);" create a getter of the c pointer inside B and then do: "delete(b.Getblabla())" save the pointer I passed as a member of A and then release it: "delete(pointer_to_c)"

do you have some elegant offers?

edit: hey some clarifications, the reason why A allocates C and passing it to B is that C is an interface and I want B to be initialized with different implementations of C depends in the situation.

Bar
  • 1
  • 1
  • 3
    Its not 'A's job to clean up 'B's resources. – tkausl Aug 25 '20 at 17:10
  • I agree with @tkausl ! Free the memory in B's destructor ^^ – Vélimir Aug 25 '20 at 17:15
  • Handy reading: [What is ownership of resources or pointers?](https://stackoverflow.com/questions/49024982/what-is-ownership-of-resources-or-pointers) – user4581301 Aug 25 '20 at 17:16
  • 1
    The design goal of making `A` responsible for `B`'s internal resources is inherently inelegant. You can't practically make it elegant. `B` should be responsible for it's own internals. – François Andrieux Aug 25 '20 at 17:16
  • Why does `A` create the `C`? It may be better if `B`'s constructor picks up that responsibility. That way `A` gets to remain blissfully ignorant of what's going in in `B`. Yay encapsulation. – user4581301 Aug 25 '20 at 17:20
  • hey, i edited the post with clarification on why i need A to create C. I'd be glad to hear your opinion – Bar Aug 25 '20 at 17:43

2 Answers2

3

A contains an object of type B. So A should not have to do any cleanup itself. Instead, B should clean up the memory, since that is the class that contains an owning pointer.

class B {
  C *c;
  public:
    B(C *c) : c(c) {} 
    ~B() { delete c; }
};

When the destructor of A runs, the destructor of B will be run, which will clean up the memory. Of course, now you will need to define the copy and move operations for B as well. See rule of 3/5/0 for more details.

Instead, B could be written like this:

class B {
  std::unique_ptr<C> c;
};

and now you don't have to do any cleanup yourself, since unique_ptr will take care of that.

cigien
  • 57,834
  • 11
  • 73
  • 112
0

The simplest and arguably cleanest is probably to just keep the C instance in A in the first place:

class A {
    CImplementation c;
    B b;
public:
    A() : b( &c ) {}
};

If you truly needed it to be dynamically allocated for some reason, use an unique_ptr< C > member and allocate the appropriate C derivative in A's initializer list.

HerrJoebob
  • 2,264
  • 16
  • 25