Question

If I call a destructor explicitly ( myObject.~Object() ) does this assure me that the object will be appropriately destroyed (calling all child destructors) ?

Ok some code:

class Object
{
   virtual ~Object()
   {}
};

class Widget : public Object
{
   virtual ~Widget()
   {}
};

...
Object* aWidget = new Widget(); //allocate and construct
aWidget->~Object(); //destroy and DON'T deallocate

I know I could just delete the object, but I don't want to. I want to keep the allocated memory handy as an important optimization.

Thanks!

Was it helpful?

Solution

The answer is... nearly always.

If your object has a non-virtual destructor, and is then sub-classed to add child elements that need freeing... then calling the destructor on the object base class will not free the child elements. This is why you should always declare destructors virtual.

We had an interesting case where two shared libraries referenced an object. We changed the definition to add child objects which needed freeing. We recompiled the first shared library which contained the object definition.

HOWEVER, the second shared library was not recompiled. This means that it did not know of the newly added virtual object definition. Delete's invoked from the second shared library simply called free, and did not invoke the virtual destructor chain. Result was a nasty memory leak.

OTHER TIPS

Yes. But holy smokes, are you sure about this? If so I would use placement new to construct your Widget. Using placement new and then explicitly calling the destructor is an acceptable, if unusual, idiom.

Edit: Consider allocating the memory yourself manually rather than using new to allocate the first object and then re-using its memory afterward. That allows you complete control over the memory; you could allocate big chunks at a time, for instance, rather than allocating a separate block of memory for each Widget. That'd be fair savings if memory really is such a scarce resource.

Also, and perhaps more importantly, you'd then be doing placement new "normally", rather than this hybrid regular new/placement new solution. I'm not saying it won't work, I'm just saying it's a rather, ah, creative solution to your memory problem.

Yes, a destructor, even when called explicitly, will destroy its subobjects properly.

As you seem to realize, it's a rare action to do, but perhaps as part of a well tested and documented library it may be useful. But document (and profile) it since even though it's valid and safe, every maintainer (including you) will never feel comfortable with it.

Yes it will call all the child destructors so it will work as you are expecting.

The destructor is just a function after all, it just so happens that it gets called when objects are deleted.

Therefore if you use this approach be careful of this:

#include <iostream>

class A
{
public: 
    A(){};
    ~A()
    {
        std::cout << "OMG" << std::endl;
    }
};

int main()
{
    A* a = new A;
    a->~A();
    delete a;
    return 0;
}

output:
OMG
OMG 

The destructor is called a second time when delete is actually called on the object, so if you delete pointers in your destructor, make sure that you set them to 0, so that the second the destructor is called nothing will happen (as deleting a null pointer does nothing).

Please save yourself some real headaches and use the Boost Object Pool, which sounds like an existing implementation of your source/sink pattern. It will allocate large chunks of memory, slice them into the correct size for your object and return them to you (after calling the constructor). When you delete objects, they have their destructor called and are put into a linked list of objects for re-use. It will grow and shrink automatically and ensure that instances of your objects tend to be close together in memory.

If nothing else, it is a good example implementation of placement new and explicit use of constructors that you could study.

Yes. A destructor calls any member destructors in LIFO order, then base class destructors, and there is no way to prevent it from calling these destructors*. The object stack is guaranteed to unwind.

Initialization and finalization are separated from memory allocation and deallocation in C++ exactly so that when the special case arises, there is an unambiguous syntax in which the application-programmer can express his or her intent to the compiler.

Edit:

  • I suppose that by invoking abort() or longjmp() one could, in fact, prevent the member and base class destructors from running.

Running the destructor does not free memory used by the object being destructed - the delete operator does that. Note, however, that the destructor may delete "child objects" and their memory will be freed as per usual.

You need to read up on placement new/delete as this allows you to control memory allocation and when constructors/destructors run.

See here for a little info:

http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.9

STL containers do this. In fact, an STL allocator must provide a destroy method that calls an object's destructor (allcators also provide a deallocate method to deallocate the memory that used to hold an object). However, the advice from Stroustrup (The C++ Programming Language 10.4.11) is

Note that explicit calls of destructors ... should be avoided wherever possible. Occassionally, they are essential. ... A novice should think thrice before calling a destructor explicitly and also ask a more experienced colleague before doing so.

Calling the destructor is fine. However, beware of the type you're calling it on. If that type doesn't have (didn't inherit) a virtual destructor, you might get unexpected behaviour.

Also, as mentioned, the destructor does not free any memory, but I guess that's the reason you want to call it manually in the first place.

Plus, unless I'm mistaken, calling the destructor manually is the only option you have if you used placement new to call the constructor.

Why destroy it at all? Just write over the memory? Are you wanting logic to execute to gracefully handle releasing resources? I am going to state emphatically that this is an abuse of the language and not a good idea.

I would consider overriding new for the objects you want special allocation and deallocation behaviour for - after all that's what it's for. A hybrid scheme of normal new and explicitly calling destructors sounds like a recipe for future headaches. For starters, any memory leak detection strategy is going to get thrown way off.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top