2

I've got 3 classes

class A
{
    A();
    virtual ~A();
}
class B : public A
{
    B();
    ~B();
}
class C
{
    void *obj;
    C() : obj(nullptr) {}
    ~C() { if (obj) delete obj; }
}

when I use class C as a container for any child of class A and try to delete C instance. A, B destructor is not inveked is it normal? What is the solutuon?

C* instance = new C();
instance.obj = new B();
//Magic
delete instance; // A and B destructor is not called
Walter
  • 44,150
  • 20
  • 113
  • 196
EOG
  • 1,677
  • 2
  • 22
  • 36
  • `delete` is very type-aware. If you `delete` a `void *` it wouldn't know the object was originally `C`. – Shahbaz Oct 03 '13 at 12:01
  • 2
    If you are using `C` as a container for "any child of class `A`", why can't you use `A *` for the type of `obj`? – CB Bailey Oct 03 '13 at 12:05
  • You [can't delete a void pointer](http://stackoverflow.com/a/18683731/596781). It' s not valid C++ and it shouldn't even compile. If it does, you're not using a real C++ compiler, and this question is not tagged appropriately. – Kerrek SB Oct 03 '13 at 12:10
  • @KerrekSB: It's not ill-formed to delete `void*`; just undefined behaviour if it isn't null. My (reasonably "real") compiler just gives a warning. – Mike Seymour Oct 03 '13 at 12:17
  • @MikeSeymour: Yes, that's better. But this is one of those warnings that you really must not ignore. It's arguably also a bit of legacy cruft in the standard. Why allow a void pointer if the only allowed value is NULL? Might as well scrap the entire thing. You can still permit `delete nullptr`. – Kerrek SB Oct 03 '13 at 12:17

3 Answers3

12

Deleting a pointer to an incompatible type (including void) gives undefined behaviour.

What is the solution?

  • use the correct type: either the type you specified with new, or a base class if it has a virtual destructor; or
  • use std::shared_ptr<void>, initialised from std::shared_ptr<correct_type>: its deleter will do the right thing.

In this case, it looks like you can simply store A* rather than void*, since you say it should be "a container for any child of class A".

By the way, there's no need to check whether the pointer is null before deleting it.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
6

You delete a void*, so delete doesn't know that it's a B* so the destructor can't be called. You have to use a class pointer if you want the destructor to be called on deletion.

For example, is all classes that may be C's obj extend A, then use an A*.

Jaffa
  • 12,442
  • 4
  • 49
  • 101
0

Yes, delete needs the specific type.

kevinwei
  • 1
  • 1