3

Relatively simple question about handling destructors properly...

First I've got a class that's something like this:

class Foo {
public:
    ReleaseObjects() {
        for (std::map<size_t, Object*>::iterator iter = objects.begin(); iter != objects.end(); iter++) {
            delete (*iter).second;
        }
        objects.clear();
    }

private:
    std::map<size_t,Object*> objects;
}

So the function simply deletes the objects, which were created using 'new'. Problem is an Object class:

class Bar : public Object {
public:
    Bar() {
        baz = new Baz();
    }

    ~Bar() { delete baz; }
private:
    Baz* baz;
}

If I add a type Baz object to Foo, and then try to ReleaseObjects(), I get a memory leak (valgrind). The issue points to baz being leaked, and I guess that means the destructor in bar is never called? So what I'd like to know is how to call the Bar destructor when trying to destroy that object (I can't alter the Bar class, but I can alter Foo).

Edit: Oops, sorry for the syntax errors. Anyways, thanks for all the replies, silly me forgot to implement a proper destructor in my Baz class! Oh, and Baz is actually a template class, but I figured Baz was sort of irrelevant to my question, and that the problem was the destructor in Bar not being called... well, I was wrong, problem is in Baz after all. But thanks again, I think I got it figured out from here!

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Fault
  • 1,239
  • 4
  • 14
  • 18
  • 6
    Is the destructor in Object virtual ? Post the Object class as well – Tom Oct 18 '11 at 17:44
  • 5
    This code did not leak. This code did not even compile. Please post actual code. – Benjamin Lindley Oct 18 '11 at 17:46
  • 1
    Can you post the class (or whatever it is) for Baz? – MGZero Oct 18 '11 at 17:47
  • 1
    Please post a minimal, complete program that demonstrates the error. See http://sscce.org for more info. – Robᵩ Oct 18 '11 at 17:47
  • 1
    What specific error do you get? And are you adding Baz to Foo, or Bar to Foo's map? The "delete (*iter).second should be triggering Bar's destructor correctly. – Joe Oct 18 '11 at 17:48
  • Also, post something error free. skimming through it, I see a few errors, a missing semi-colon after delete baz for example. – MGZero Oct 18 '11 at 17:49
  • 1
    Calling delete on the Bar object in Foo calls the the Bar destructor. Also, is the Baz destructor defined? It could be that Baz is not properly cleaning itself up. –  Oct 18 '11 at 17:53
  • 1
    [Use RAII!](http://stackoverflow.com/questions/76796/memory-management-in-c/77893#77893) – sbi Oct 18 '11 at 18:01

3 Answers3

6

You've got to make sure that your destructor is virtual so that the proper derived destructor is called.

class Object {
 . . .
 virtual ~Object()
 . . .
};
zdan
  • 28,667
  • 7
  • 60
  • 71
  • This is pretty much what I forgot to implement! And I thought my problem was something else entirely... thanks! – Fault Oct 18 '11 at 17:59
2

I don't fully understand your scenario, but since you've got public inheritance, you probably want virtual destructors. In particular, the base class (Object) needs a virtual destructor.

Note that your given code cannot compile. The new operator returns a pointer, so baz must be a pointer.

Oscar Korz
  • 2,457
  • 1
  • 18
  • 18
0

You should always always use smart pointers. These types behave like pointers but release memory automatically, and void the need for any such functions. They avoid all sorts of nasty bugs- potentially including this one, if you used a shared_ptr<Bar> and casted it down.

If you want to write non-trivial software in C++, you must know and understand smart pointers.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • If the problem is a non-virtual destructor, I don't think a shared_ptr will work. (Not 100% sure though) – Mooing Duck Oct 18 '11 at 18:00
  • @MooingDuck: It uses type erasure for the destructor, and therefore *will* avoid this problem if you started at `Bar`. – Puppy Oct 18 '11 at 18:01