Desctructor, finalizer, and Dispose - Part 1.managed C++ extension in V1.X
As a C++ fan, I'm a long time admirer for deterministic finalization. I think introduction of garbage collection to C style language by Java and .Net is a huge improvement. However, I found lose of deterministic destructor is almost unacceptable when I first enter Java/.Net world. Of course I'm used to it now, but it's still quite confusing to me for C# to use C++ destructor syntax for Finalizer. And in managed extension of C++, destructor becomes something totally different for managed data type. I bet a lot of experienced C++ developers make mistake to use finalizer as if it was destructor when they first try .Net. So when I read the new changes in Whidbey version of C++ from Stan Lippman's blog, I'm very excited and can't wait to give it a try.
But before we look into the new features, let's go over how old version of managed C++ handles destructors. I wrote this simple program:
#using <mscorlib.dll>
using namespace System;
__gc class RefT
{
public:
RefT () {Console::WriteLine ("RefT::RefT");}
~RefT () {Console::WriteLine ("RefT::~RefT");}
};
__value class ValueT
{
ValueT () {Console::WriteLine ("ValueT::ValueT");}
//destructor is not allowed for value type
};int main()
{
{ //1. auto-generated finalizer will be called in asynchronizied fashion
RefT * prt = new RefT;
}{ //2. Dispose is called at “delete” and finalizer will be suppressed
RefT * prt = new RefT;
delete prt;
}{
ValueT vt;
}
{
//value type can't be created in GC heap
ValueT * pvt = __nogc new ValueT;
delete pvt;
}
return 0;
}
I compiled it with V1.1 C++ compiler and checked generated IL code using ildasm. RefT is compiled to something like this:
class RefT
{
RefT ()
{
Console.WriteLine (“RefT::RefT”);
}void Finalize ()
{
Console.WriteLine (“Ref::~Ref”);
}void __dtor ()
{
GC.SuppressFinalize (this);
Finalize ();
}
}
Here we could see that C++ destructor is mapped to CLR finalizer and a method “__dtor” is added to call finalizer and SupressFinalize.
In main, the first block creates a RefT object in heap and leaves it as garbage. Sometime later, finalizer (~RefT) will run and the object will be collected. In the second block, we “delete” the object. This is translated into a call to __dtor in IL. So “delete” acts more like Dispose method recommended by IDisposable pattern: the object is not freed but the contents are disposed and finalizer won't run on the object later.
Comments
- Anonymous
June 07, 2009
PingBack from http://greenteafatburner.info/story.php?id=4275