Exception unwinding base destructor called - why?

From: Douglas Peterson (Tergiver_at_nospam.msn.com)
Date: 06/24/04


Date: Thu, 24 Jun 2004 02:18:15 -0400

Take a look at this code, it looks funny as its written to be as short as
possible:

-- code --
struct Base
{
 ~Base() { *((char*)0) = 0; }
};

struct Derived : public Base
{
 Derived() { throw 1; }
};

int main(int,char**)
{
 try { new Derived; }
 catch (int) { }
 return 0;
}
-- code --

Now don't get excited about the *((char*)0) = 0, I'm just using that as a
kind of compiler independent, hard coded breakpoint. I want to verify that
the destructor is in fact getting called without relying on a debugger set
breakpoint which can sometimes not occur, or the code be optimized out so
that there is no point to break on.

So what are we looking at?

We are creating an instance of Derived inside an exception handler. During
construction Derived throws an exception and the handler's unwinding
mechanism is calling the destructor for the base class.

My question is: Why?

Where is the logic in partially deconstructing an aggregate object that's
signaling it cannot be constructed by way of an exception? If you move the
...ahem... breakpoint to Derived's destructor, that never gets called. Makes
sense not to deconstruct an object that's not fully constructed, so again,
why partially deconstruct it?

The other thing that doesn't make sense to me is that this object is not
being created on the stack, so why would *any* destructor be called by the
unwinding mechanism? There is no call to delete anywhere in the code, so
what makes the compiler think it should be deconstructed at all?

You may have guessed that I'm having chicken and egg problems and you'd be
correct. Now I *think* I can fix the problem by rearraging order of
operations in my constructors (although I have not at this point worked out
the details, and of course that adds a degree of complexity to the code I'd
rather avoid), but I'd really like to understand the reasoning behind this.
Perhaps I'm doing something fundamentally 'wrong' and need to rethink my
design (I sure hope not!).



Relevant Pages

  • Re: Go ahead. Stop programming. This ensures you from any mistakes.
    ... construction of which fails. ... Both in destructor, which is called by user, and in constructor, ... constructor should clear up all resources if an exception is thrown ... need them - but they help readability. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: I cannot see the need for auto_ptr?!
    ... >> No copy construction for a, and the copy constructor clearly works. ... >Point destructor ... RVO and NRVO are two different things. ...
    (comp.lang.cpp)
  • Re: throwing exception from constructor
    ... Beware that the finalizer will be called in C# even on exceptional ... thrown in the user defined constructor, the user defined destructor will ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: I cannot see the need for auto_ptr?!
    ... Julián Albo wrote: ... > No copy construction for a, and the copy constructor clearly works. ... Point destructor ... Point assignment --- ...
    (comp.lang.cpp)