By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
443,706 Members | 2,046 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 443,706 IT Pros & Developers. It's quick & easy.

exceptions in diamond's destructors

P: n/a
Hi everyone,
Suppose we have a diamond shaped diagram:

A
/ \
B1 B2
\ /
C

and assume that C' constructor invokes

A, B1, B2, C

C's destructors then are called in the reverse:

C, B2, B1, A

What is SUPPOSED to hapen if ~B2() throws an exception?
I would think, that ~B1() and ~A() should be called to finish the
destruction of C (just like in case if we were constructing C and there
was an exception in B2's constructor), however, some popular compilers
give different results (below is the sequence of destructors called to
destroy C with an exception thrown in B2):

gcc-3.3 and up: C, B2, B1, A // seems to be OK
Intel icc9: C, B2, A, B1 , A // ~A() called twice!
MS VC6/2005Express: C, B2, B1 // where is ~A() ?

So, what standard says about this situation? Is it undefined or gcc is
right?

Regards,
Vladimir

Below is a short program to demonstrate the behavior:
///////////////////////////////////////////////////////////////
#include <iostream>

using namespace std;
struct A {~A() {cout << "A" <<endl;}};
struct B1 : public virtual A {~B1() {cout << "B1" <<endl;}};
struct B2 : public virtual A {
~B2() {
cout << "B2" <<endl;
throw "bad things happened";
}
};
struct C : public B1, public B2 {~C() {cout << "C" <<endl;}};
int main(int argc, char* argv[])
{
try {
C * p = new C;
delete p;
} catch (...) {};
return 0;
}

//////////////////////////////////

Nov 22 '05 #1
Share this Question
Share on Google+
17 Replies


P: n/a

<vg********@gmail.com> wrote in message
news:11**********************@g47g2000cwa.googlegr oups.com...
Hi everyone,
Suppose we have a diamond shaped diagram:

A
/ \
B1 B2
\ /
C

and assume that C' constructor invokes

A, B1, B2, C

C's destructors then are called in the reverse:

C, B2, B1, A

What is SUPPOSED to hapen if ~B2() throws an exception?
I would think, that ~B1() and ~A() should be called to finish the
destruction of C (just like in case if we were constructing C and there
was an exception in B2's constructor), however, some popular compilers
give different results (below is the sequence of destructors called to
destroy C with an exception thrown in B2):

gcc-3.3 and up: C, B2, B1, A // seems to be OK
Intel icc9: C, B2, A, B1 , A // ~A() called twice!
MS VC6/2005Express: C, B2, B1 // where is ~A() ?

So, what standard says about this situation? Is it undefined or gcc is
right?


I'm not sure what the standard says about throwing an exception
from a destructor, but every 'how to write C++ code' book I've
read addresses the issue like so: Don't Do That. And IMO combining
this questionable practice with the already sticky issues of 'diamond
inheritance' will only further decrease code coherence.

I think the better issue to discuss is why you might feel
you *need* a destructor to throw. IOW look at your *design*.

But that's just my opinion. :-) I'll let the true gurus explain
the technical details.

-Mike
Nov 22 '05 #2

P: n/a
My true reason to ask is to prove superiority of gcc, of course :)
Jokes aside, I came accross it by curiosity and got even more
interested when the compilers I have access to disagreed on the answer.
On the other hand, I can see it happens in practice if you call other
functions inside a destructor and one of them throws.
- Vladimir

Nov 22 '05 #3

P: n/a
vg********@gmail.com wrote:
My true reason to ask is to prove superiority of gcc, of course :)
Jokes aside, I came accross it by curiosity and got even more
interested when the compilers I have access to disagreed on the answer.
On the other hand, I can see it happens in practice if you call other
functions inside a destructor and one of them throws.
- Vladimir


That's just it though - Destructors should never have the chance to
throw. If something else has already thrown an exception, and the
current object is being destructed, another exception, and you're dead.

Nov 22 '05 #4

P: n/a
> I think the better issue to discuss is why you might feel
you *need* a destructor to throw. IOW look at your *design*.


If you use RAII also for handling hardware (files, communication
channels...), then it might fail while you are closing and in that case I
would like to throw. If I remember correctly, there is a function that you
can call to determine, if you are already unwinding the stack due to another
throw. Is that function part of the standard or implementation specific ?

But in any case the standard should ensure that objects going out of scope
should be destroyed, so it seems gcc is the only one getting it right.

Niels Dybdahl
Nov 22 '05 #5

P: n/a

Niels Dybdahl skrev:
I think the better issue to discuss is why you might feel
you *need* a destructor to throw. IOW look at your *design*.
If you use RAII also for handling hardware (files, communication
channels...), then it might fail while you are closing and in that case I
would like to throw. If I remember correctly, there is a function that you
can call to determine, if you are already unwinding the stack due to another
throw. Is that function part of the standard or implementation specific ?


There is (it is named uncaught_exception if my memory is correct), but
is it really such a good idea to use it? You now have two ways of
specifying an error which leads to extra trouble. Also, if you can't
release a resource (as is the case in the problem we are discussing),
something is seriously wrong and it might be a better idea to terminate
the program.

/Peter
But in any case the standard should ensure that objects going out of scope
should be destroyed, so it seems gcc is the only one getting it right.

Niels Dybdahl


Nov 22 '05 #6

P: n/a
> > > I think the better issue to discuss is why you might feel
you *need* a destructor to throw. IOW look at your *design*.
If you use RAII also for handling hardware (files, communication
channels...), then it might fail while you are closing and in that case I would like to throw. If I remember correctly, there is a function that you can call to determine, if you are already unwinding the stack due to another throw. Is that function part of the standard or implementation specific

?
There is (it is named uncaught_exception if my memory is correct), but
is it really such a good idea to use it? You now have two ways of
specifying an error which leads to extra trouble. Also, if you can't
release a resource (as is the case in the problem we are discussing),
something is seriously wrong and it might be a better idea to terminate
the program.


It is not nice to close a GUI application, just because a hardware error
occurs.
F.ex if the application is writing a document to a removable disk and the
disk is removed just before the destructor closes the file, you can not be
sure that the document is properly written. You should allow the user to
save the document somewhere else before closing the application.

Once I was using this approach and checked uncaught_exception to find out if
it was safe to throw an exception, but it turned out that I could not trust
uncaught_exception in MSVC6, so I had to give it up. So do not use
destructors to flush data or free resources if it might fail. There are
simply too many bad implementations.

Niels Dybdahl
Nov 22 '05 #7

P: n/a

vg********@gmail.com wrote:
My true reason to ask is to prove superiority of gcc, of course :)
Jokes aside, I came accross it by curiosity and got even more
interested when the compilers I have access to disagreed on the answer.
On the other hand, I can see it happens in practice if you call other
functions inside a destructor and one of them throws.
- Vladimir


To add to some of the responses from others, this subject is discussed
in the FAQ

http://www.parashift.com/c++-faq-lit....html#faq-17.3

Gavin Deane

Nov 22 '05 #8

P: n/a
Okay, let's not mix definition of the language and best practices. If
throwing exception inside a destructor is legal, then standard should
one way or another describe what will happen with yet undestroyed
subclasses. That is my original question and that is what I want to
understand.

Another thing is that you don't need a diamond diagram: VC2005 doesn't
call base class destructor even if exception is thrown in ~B() for
A<-B<-C diagram (~A is not called).

Regards,
Vladimir

Nov 22 '05 #9

P: n/a
Okay, let's not mix definition of the language and best practices. If
throwing exception inside a destructor is legal, then standard should
one way or another describe what will happen with yet undestroyed
subclasses. That is my original question and that is what I want to
understand.

Another thing is that you don't need a diamond diagram: VC2005 doesn't
call base class destructor even if exception is thrown in ~B() for
A<-B<-C diagram (~A is not called).

Regards,
Vladimir

Nov 22 '05 #10

P: n/a
* vg********@gmail.com:
Hi everyone,
Suppose we have a diamond shaped diagram:

A
/ \
B1 B2
\ /
C

and assume that C' constructor invokes

A, B1, B2, C

C's destructors then are called in the reverse:

C, B2, B1, A

What is SUPPOSED to hapen if ~B2() throws an exception?
15.2/2, emphasis added:
"An object that is partially constructed or _partially destroyed_ will
have destructors executed for all of its fully constructed subobjects".

However, the implicit context here, from 15.2/1, is destruction of
automatic objects due to an exception.

Your example program use dynamic allocation.

I would think, that ~B1() and ~A() should be called to finish the
destruction of C (just like in case if we were constructing C and there
was an exception in B2's constructor)
Yep, I would also think that.

, however, some popular compilers
give different results (below is the sequence of destructors called to
destroy C with an exception thrown in B2):

gcc-3.3 and up: C, B2, B1, A // seems to be OK
Intel icc9: C, B2, A, B1 , A // ~A() called twice!
MS VC6/2005Express: C, B2, B1 // where is ~A() ?

So, what standard says about this situation? Is it undefined or gcc is
right?


The way I read the probable _intention_ of the standard g++ is right,
but the standard could be more clear...

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Nov 22 '05 #11

P: n/a
vg********@gmail.com wrote:
Okay, let's not mix definition of the language and best practices. If
throwing exception inside a destructor is legal, then standard should
one way or another describe what will happen with yet undestroyed
subclasses.

The standard already describes this (15.2.2):

An object that is partially constructed or partially destroyed will
have destructors executed for all of its fully constructed subobjects,
that is, for subobjects for which the constructor has completed
execution and the destructor has not yet begun execution.

Another thing is that you don't need a diamond diagram: VC2005 doesn't
call base class destructor even if exception is thrown in ~B() for
A<-B<-C diagram (~A is not called).

I think this falls under the category quoted above (see 10.2 for a
confirmation of this). So if ~A() is not executed, then the compiler
is broken.

Hope this helps,
-shez-

Nov 22 '05 #12

P: n/a
In article <43**********************@dread11.news.tele.dk>,
Niels Dybdahl <nd*@esko-graphics.com> wrote:
But in any case the standard should ensure that objects going out of scope
should be destroyed, so it seems gcc is the only one getting it right.


I may have lost the context, but what is it that only hcc gets right?
And right according to what?
--
Greg Comeau / Celebrating 20 years of Comeauity!
Comeau C/C++ ONLINE ==> http://www.comeaucomputing.com/tryitout
World Class Compilers: Breathtaking C++, Amazing C99, Fabulous C90.
Comeau C/C++ with Dinkumware's Libraries... Have you tried it?
Nov 22 '05 #13

P: n/a

Niels Dybdahl skrev:
> I think the better issue to discuss is why you might feel
> you *need* a destructor to throw. IOW look at your *design*.

If you use RAII also for handling hardware (files, communication
channels...), then it might fail while you are closing and in that case I would like to throw. If I remember correctly, there is a function that you can call to determine, if you are already unwinding the stack due to another throw. Is that function part of the standard or implementation specific
?

There is (it is named uncaught_exception if my memory is correct), but
is it really such a good idea to use it? You now have two ways of
specifying an error which leads to extra trouble. Also, if you can't
release a resource (as is the case in the problem we are discussing),
something is seriously wrong and it might be a better idea to terminate
the program.


It is not nice to close a GUI application, just because a hardware error
occurs.
F.ex if the application is writing a document to a removable disk and the
disk is removed just before the destructor closes the file, you can not be
sure that the document is properly written. You should allow the user to
save the document somewhere else before closing the application.


In that case, your destructor does to much. You should presumably have
some logic to flush the file (e.g. doing FlushFileBuffers if you
program in Windows). The code to do this stuff does not look as if
belongs in a destructor but in a separate piece of code.
Once I was using this approach and checked uncaught_exception to find out if
it was safe to throw an exception, but it turned out that I could not trust
uncaught_exception in MSVC6, so I had to give it up. So do not use
destructors to flush data or free resources if it might fail. There are
simply too many bad implementations. I believe this is still the case although i'm not sure about 8.0. I
tried to use uncaught_exception for tracing purposes but as you had to
give up with VC++ 6.0.

/Peter
Niels Dybdahl


Nov 22 '05 #14

P: n/a
> >But in any case the standard should ensure that objects going out of
scope
should be destroyed, so it seems gcc is the only one getting it right.


I may have lost the context, but what is it that only hcc gets right?
And right according to what?


According to the tests performed by the original poster, only gcc cleans
properly when an exception is thrown in a destructor.
Intels compiler destroyed one object twice afterwards and Microsofts forgot
to destroy one of the objects.
In addition you can not rely upon that Microsofts compiler sets
uncaught_exception correctly.

Niels Dybdahl
Nov 22 '05 #15

P: n/a
> > > > > I think the better issue to discuss is why you might feel
> > you *need* a destructor to throw. IOW look at your *design*.
>
> If you use RAII also for handling hardware (files, communication
> channels...), then it might fail while you are closing and in that case
I
> would like to throw. If I remember correctly, there is a function
that you
> can call to determine, if you are already unwinding the stack due to

another
> throw. Is that function part of the standard or implementation
specific ?

There is (it is named uncaught_exception if my memory is correct), but
is it really such a good idea to use it? You now have two ways of
specifying an error which leads to extra trouble. Also, if you can't
release a resource (as is the case in the problem we are discussing),
something is seriously wrong and it might be a better idea to
terminate the program.


It is not nice to close a GUI application, just because a hardware error
occurs.
F.ex if the application is writing a document to a removable disk and

the disk is removed just before the destructor closes the file, you can not be sure that the document is properly written. You should allow the user to
save the document somewhere else before closing the application.


In that case, your destructor does to much. You should presumably have
some logic to flush the file (e.g. doing FlushFileBuffers if you
program in Windows). The code to do this stuff does not look as if
belongs in a destructor but in a separate piece of code.


The only reason I can see not to put flushing and closing commands, that
might throw, into a destructor, is the flaws in the compilers. But that
reason is enough not to do it.

Niels Dybdahl
Nov 22 '05 #16

P: n/a
In article <43**********************@dread11.news.tele.dk>,
Niels Dybdahl <nd*@esko-graphics.com> wrote:
>But in any case the standard should ensure that objects going out ofscope >should be destroyed, so it seems gcc is the only one getting it right.


I may have lost the context, but what is it that only hcc gets right?
And right according to what?


According to the tests performed by the original poster, only gcc cleans
properly when an exception is thrown in a destructor.
Intels compiler destroyed one object twice afterwards and Microsofts forgot
to destroy one of the objects.
In addition you can not rely upon that Microsofts compiler sets
uncaught_exception correctly.


Ok, that sound about right. FYI, Comeau also provides C, B2, B1, A
which appears to be correct, though the advise "don't do that"
is reasonable.
--
Greg Comeau / Celebrating 20 years of Comeauity!
Comeau C/C++ ONLINE ==> http://www.comeaucomputing.com/tryitout
World Class Compilers: Breathtaking C++, Amazing C99, Fabulous C90.
Comeau C/C++ with Dinkumware's Libraries... Have you tried it?
Nov 22 '05 #17

P: n/a

Niels Dybdahl skrev:
> > > I think the better issue to discuss is why you might feel
> > > you *need* a destructor to throw. IOW look at your *design*.
> >
> > If you use RAII also for handling hardware (files, communication
> > channels...), then it might fail while you are closing and in that case I
> > would like to throw. If I remember correctly, there is a function that you
> > can call to determine, if you are already unwinding the stack due to
another
> > throw. Is that function part of the standard or implementation specific ?
>
> There is (it is named uncaught_exception if my memory is correct), but
> is it really such a good idea to use it? You now have two ways of
> specifying an error which leads to extra trouble. Also, if you can't
> release a resource (as is the case in the problem we are discussing),
> something is seriously wrong and it might be a better idea to terminate > the program.

It is not nice to close a GUI application, just because a hardware error
occurs.
F.ex if the application is writing a document to a removable disk and the disk is removed just before the destructor closes the file, you can not be sure that the document is properly written. You should allow the user to
save the document somewhere else before closing the application.
In that case, your destructor does to much. You should presumably have
some logic to flush the file (e.g. doing FlushFileBuffers if you
program in Windows). The code to do this stuff does not look as if
belongs in a destructor but in a separate piece of code.


The only reason I can see not to put flushing and closing commands, that
might throw, into a destructor, is the flaws in the compilers. But that
reason is enough not to do it.


Well.... i doubt that a reasonably written destructor could do what is
required in case of a disk error. This requires user intervention and
quite complex code which should not be put in a destructor (among other
reasons because destructors should not throw).

/Peter
Niels Dybdahl


Nov 22 '05 #18

This discussion thread is closed

Replies have been disabled for this discussion.