Does calling a destructor explicitly destroy an ob

2019-01-11 23:40发布

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!

11条回答
萌系小妹纸
2楼-- · 2019-01-11 23:57

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.

查看更多
我只想做你的唯一
3楼-- · 2019-01-11 23:58

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.

查看更多
疯言疯语
4楼-- · 2019-01-11 23:58

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).

查看更多
做自己的国王
5楼-- · 2019-01-11 23:59

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.

查看更多
疯言疯语
6楼-- · 2019-01-12 00:04

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
查看更多
Explosion°爆炸
7楼-- · 2019-01-12 00:10

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.

查看更多
登录 后发表回答