Now I'm confused (C++/CLI destructors)

| 2 Comments
So here I am, writing a piece about how the C++/CLI destructor and finalizer stuff could have been a bit neater and I put together some sample code to demonstrate my point and it doesn't do what the docs I mentioned yesterday suggest that it should do...

Given this example class....

ref class Example
{
   public :
   
      Example(
         bool throws)
         : m_count(s_count++),
            m_string(gcnew String("MyString"))
      {
         Console::WriteLine(m_count + " - Example(throws = " + throws + ")");

         if (throws)
         {
            throw "Thrown";
         }
      }
   
      Example()
         : m_count(s_count++),
            m_string(gcnew String("MyString"))
      {
         Console::WriteLine(m_count + " - Example");
      }
   
      ~Example()
      {
         Console::WriteLine(m_count + " - ~Example");

         delete m_string;
	
         this->!Example();            
      }

      !Example()
      {
         Console::WriteLine(m_count + " - !Example");
      }

   private :

      const int m_count;

      String ^m_string;

      static int s_count = 0;
};

And the following test code...

int main(array<System::String> ^args)
{
   try
   {
      Example example(true);
   }
   catch(...)
   {
      Console::WriteLine("Caught");
   }
   
   try
   {
      Example ^example = gcnew Example(true);
   }
   catch(...)
   {
      Console::WriteLine("Caught");
   }
    
   return 0;
}

I was expecting, based on these docs from MSDN, that the output would be something like this:

0 - Example
0 - ~Example
0 - !Example
Caught
1 - Example
Caught
1 - !Example

But, instead, I actually get this:

0 - Example
Caught
1 - Example
Caught
1 - !Example
0 - !Example

That is, the destructor for the stack based object isn't called (as the docs seem to imply it would be), but the finalizers are when the objects are garbage collected...

Am I being dense here?

2 Comments

If the constructor throws an expection why do you expect the the Dispose-Method (~T) should be called!?
It just calls the finilizer because the GC-object was successfully created...

Form my point of view it is a "normal" behaviour.

Simply because that's what the docs say over at MSDN...

http://msdn2.microsoft.com/en-us/library/ms177197.aspx

Code authored in Visual C++ and compiled with /clr will run a type's destructor for the following reasons:

If an object created using stack semantics goes out of scope. For more information, see C++ Stack Semantics for Reference Types.

If an exception is thrown during the object's construction.

...

I agree that it's seems more sensible for the destructor/dispose not to run, but the docs seem to say that it will... Hence my confusion.

Leave a comment

About this Entry

Something all C++ programmers should know when using managed C++ was the previous entry in this blog.

Detecting the Excel Function Wizard is the next entry in this blog.

I usually write about C++ development on Windows platforms, but I often ramble on about other less technical stuff...

Find recent content on the main index or look in the archives to find all content.

I have other blogs...

Subscribe to feed The Server Framework - high performance server development
Subscribe to feed Lock Explorer - deadlock detection and multi-threaded performance tools
Subscribe to feed l'Hexapod - embedded electronics and robotics
Subscribe to feed MegèveSki - skiing