"Douglas Peterson" <Tergiver@nospam.msn.com> wrote in message
news:Uradnc5W-JW170fdRVn-vw@comcast.com...[color=blue]
> 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?[/color]
Because its useful.
[color=blue]
>
> 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.[/color]
Makes[color=blue]
> sense not to deconstruct an object that's not fully constructed, so again,
> why partially deconstruct it?[/color]
The Base object is fully constructed, do you want Base objects to be handled
differently depending on whether they are part of a larger object or not?
All fully constructed objects should be destructed.
[color=blue]
>
> 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?[/color]
It's not the unwinding mechanism. Its how constructors behave when an
exception occurs in a constructor. All this is happening before stack
unwinding starts.
[color=blue]
> There is no call to delete anywhere in the code, so
> what makes the compiler think it should be deconstructed at all?[/color]
Because a Base object has been fully constructed. Suppose the Base object
constructor had allocated some memory which was freed in the destructor. If
the destructor were not called there would be a memory leak.
[color=blue]
>
> You may have guessed that I'm having chicken and egg problems and you'd be
> correct.[/color]
Actaully I don't see why you have a problem at all.
[color=blue]
> Now I *think* I can fix the problem by rearraging order of
> operations in my constructors (although I have not at this point worked[/color]
out[color=blue]
> the details, and of course that adds a degree of complexity to the code[/color]
I'd[color=blue]
> rather avoid), but I'd really like to understand the reasoning behind[/color]
this.[color=blue]
> Perhaps I'm doing something fundamentally 'wrong' and need to rethink my
> design (I sure hope not!).
>[/color]
I think so. Have a look at this article by Bjarne Stroustrup which explains
how to use this language feature to write cleaner more exception safe code.
http://www.research.att.com/~bs/3rd_safe.pdf
john