Is it valid to directly call a (virtual) destructor?
Asked Answered
C

3

8

In this answer, Ryan directly calls the virtual destructor. I've tested the code in VS2010, and it correctly calls all destructors (tested with logging statements). Is it actually valid to do so? What are the problems, flaws or even the good points of such an approach?

I can only think of it as a way to really force a reset of the actual type, even if they don't override a virtual reset function, since they atleast have to clean up in their destructors.

Also, eactly what kind of side-effects does a call to the destructor bring? Is it undefined behaviour to use the object after such a destructor call? What if one immediatly reinitializes it with a new (this) MyClass(); call?

Cymophane answered 17/5, 2011 at 19:30 Comment(9)
The same rules apply to direct destructor calling as apply to using delete.Schlimazel
The new (this) MyClass(); is basically the only thing that you can do with the object after calling the destructor (i.e. reconstructing it).Bushman
@dribeas: and even that's a bit dubious - if the constructor can't fail then you get away with it (although IIRC for non-POD classes you've still invalidated pointers and references to the object, although I may not remember correctly). But that question talks about "thousands of lines of code", so I'm guessing one of those can fail. You're left with an object that isn't constructed. So you can't return or throw from reset(), because if you do then someone's going to (invalidly) attempt to destroy it later. Possibly you could terminate().Ormond
@SteveJessop "you've still invalidated pointers and references to the object, although I may not remember correctly" you don't remember correctlyGiulio
@curiousguy: I think I was referring to 3.8/7 of C++03: the conditions under which such references are still valid are quite complex.Ormond
@SteveJessop The condition of getting back to life an object is quite simple: "do nothing questionable".Giulio
@curiousguy: sure, that's simple, if you can remember the definition in 3.8/7 of "questionable". Shame we can't reduce the whole C++ standard to the simple rule, "do nothing invalid". The part that (in my experience) surprises people is that there must be no const objects involved, and I suspect that another potential source of bugs is that you can't in general destroy an object of a derived type (via its virtual destructor) and then re-create it as a base type.Ormond
@SteveJessop I am extremely surprised: did you expect that you could legally reinitialise a const variable?Giulio
@SteveJessop Forbidden operations are attempts to redefine a const variable, a reference, or to change the real type of an object. BTW, don't forget that it is also forbidden to just observe a legal change to the value of a const variable.Giulio
H
4

Calling a destructor manually is a perfectly valid thing, regardless of if it's virtual. You just want to make sure that it's just called once for every constructor call.

Is it undefined behaviour to use the object after such a destructor call? 

Yes.

What if one immediatly reinitializes it with a new (this) MyClass(); call?

Still horrifically undefined.

Do not manually destruct an object unless you had to manually place it, e.g. with placement new or some equivalent, and definitely do not ever re-initialize a destructed object like that and hope to avoid UB. Classes like std::vector very explicitly make accessing destroyed objects UB, and it remains UB even if you then make a new element in it's place.

Highhat answered 17/5, 2011 at 19:31 Comment(9)
"it's just called once" + "for every constructor call" = +1Desert
So it would be undefined behaviour to actually do so, since any object will be either cleaned up on the stack or through a delete call afterwards? (Memory leaks aside.)Cymophane
@Xeo: Not true. You just need to make sure that for every destructor called the constructor has previously been called. Though this will usually also involve the use of placement new at some point to accomplish.Springbok
@Xeo: Not if you reconstruct it: type x; ~x; new (&x) type();Bushman
@Xeo: If you use placement new, then there will be no heap delete or stack unwind to delete the object.Highhat
@John Dibling: Added, and I'm a repwhore- sue me :PHighhat
@DeadMG: +1'ed, and you can be expecting a visit from my lawyer in the next few days.Desert
"Classes like std::vector very explicitly make accessing destroyed objects UB, and it remains UB even if you then make a new element in it's place." Hug?Giulio
So what does happen in a vector then? A std::vector can hold classes with non-trivial ctor+dtor and it surely has to do placement new and explicit dtors, doesn't it?Tallman
H
1

An example of valid use involving one and only one construction:

typedef boost::aligned_storage<
    sizeof(T), boost::alignement_of<T>::value>::type arena_type;
arena_type arena;
T* p = new (&arena) T();
p->~T();
// Don't touch p now

This can be useful when e.g. implementing a variant type (warning: exception-safety left as an exercise to the reader). C++0x unrestricted unions will have similar uses for class types.

Note that for a class type, the above would be UB if you did not call the destructor.

Hart answered 17/5, 2011 at 19:49 Comment(3)
Why could you now NOT do another placement new? Is it because the placement new returns a pointer p that might be different to &arena? I assume so, but this is what is confusing me.Tallman
@Tallman you can re-use the arena to construct a different object, if you’re careful enough (and don’t forget to pair it with the appropriate destructor call)Hart
I put that in a separate question aggregating all I could find: #48707981 The point is your "careful". It seems to be amazingly hard to be "careful enough"Tallman
A
0

As long as you are calling placement new on top of your pre-allocated chunk of POD memory, its perfectly valid to deallocate invoking any destructor, virtual or not.

placement new and explicit deallocator invocation will just invoke the constructor and destructor in the referenced areas, so memory allocation is effectively factored out of the object lifecycle

Amuse answered 17/5, 2011 at 19:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.