Revive object from destructor in C++?
Disclaimer: I know this is bad design, I am simply asking the question out of curiosity in order to try to obtain deeper knowledge of how the destructor works in C++.
In C#, one can write: GC.KeepAlive(this)
in the destructor of a class (see edit below), and that would mean that the object will still be alive in memory even after the destructor call is complete.
Does the design of C++ allow reviving an object from the destructor similar to the C# algorithm described above?
Edit: As pointed out by an answer below, GC.ReRegisterForFinalize()
is more closely related to the question than GC.KeepAlive(this)
.
Solution 1:
The short answer is: no. C++ does not employ garbage collection, like Java or C#. When an object is destroyed, it's destroyed immediately. Gone for good. Joined the choir invisible. Pining for the fjords, etc...
And to say this over a couple of times in different words so that there is no possible weasily reinterpretation...
The destructor is invoked as part of object destruction. Object destruction consists of invoking the destructor and deallocating the memory that was used for the object itself. It's a single process, not two separate processes. While the destructor is running, the object still exists, for the destructor to use, but it exists on borrowed time. It's a foregone conclusion that the object is going to be vaporized as soon as the destructor returns. Once a destructor is invoked, the object is going to be destroyed, and nothing is going to change its fate.
Understand this: the reason why a destructor is being invoked is because either: the object was originally allocated on the heap with "new", and it's now being "delete"d. "delete" means "delete", not "delete maybe". So the object's getting deleted. Or, if the object was allocated on the stack, the execution thread exited the scope, so all objects declared in the scope are getting destroyed. The destructor is, technically, getting invoked as a result of the object being destroyed. So, the object is being destroyed. The End.
Having said that, C++ allows you to implement a custom allocator for your classes. If you feel like it, you can write your own custom memory allocation and deallocation functions that implement whatever functionality you want. Though these are never used for stack allocated objects (i.e. local variables).
Solution 2:
You are actually misrepresenting what GC.KeepAlive
does in .NET. It is not to be used in a destructor of an object to keep that object from being destructed -- actually, GC.KeepAlive()
is empty and has no implementation.
See the .NET source code here.
It makes sure that the object passed as a parameter is not garbage collected before the call to GC.KeepAlive
happens. The object passed to KeepAlive as a parameter can be garbage collected immediately after the call to GC.KeepAlive
. Since KeepAlive
has no actual implementation, this happens purely based on the fact that the compiler has to maintain a reference to the object to be passed as a parameter to KeepAlive
. Any other function (that is not inlined by the compiler or runtime) taking the object as a parameter could be used instead as well.
Solution 3:
Here's an idea:
C* gPhoenix= nullptr;
C::~C ()
{
gPhoenix= new C (*this); // note: loses any further-derived class ("slice")
}
Now if the objects involved (bases or members) really do have destructors that do something, this runs into a problem if you delete gPhoenix;
so you'll need more elaborate mechanisms depending on what it's really trying to accomplish. But you don't have any real goals, just curious exploration, so pointing this out should suffice.
When the body of the destructor is called, the object is still perfectly good. It appears perfectly vital and normal as you make normal member function calls from within the destructor.
The memory owning the object will be reclaimed, so you can't stick around in-place. And after leaving the body, other destruction takes place automatically and can't be interfered with. But, you can duplicate the object before that happens.
Solution 4:
As has already been pointed out, GC.KeepAlive
doesn't do that.
As long as .NET goes, it is possible to resurrect from the finalizer using GC.ReRegisterForFinalize
, you can still get a reference to it if you have a WeakReference
or GCHandle
tracking ressurection, or just give this
to something outside the class. Doing that will abort the destruction.
That is a old trick to detect garbage collection in .NET 2.0 no longer relevant, but still works (kinda, garbage collection can now be partial, and done in parallel with other threads).
Emphasis should be put on the fact that on .NET you are using a finalizer, which runs before destruction, and can prevent it. So, while it is technically correct that you can't recover an object after destruction - in any language - you can get close to the behaviour you describe in .NET, except using GC.ReRegisterForFinalize
instead.
On C++, you have already been given the correct answer.
Solution 5:
That's not possible in any language.
Your understanding is a bit off.
GC.KeepAlive
will mark the object as not collectible by the garbage collector. This will prevent the garbage collection strategy from destroying the object and it's useful if the object is used in unmanaged code where the garbage collector can't keep track of usage. This doesn't mean that the object is in memory after destruction.
Once an object begins the destruction the code will free resources (memory, file handlers, network connections). The order is usually from the deepest derived class back to the base class. If something in the middle were to prevent the destruction there's no guarantee that these resources could be re-acquired and the object would be in an inconsistent state.
What you want more likely is to have a std::shared_ptr
that keeps track of copies and references and only destroys the object once nobody needs it anymore.