473,398 Members | 2,165 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,398 software developers and data experts.

exceptions in diamond's destructors

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
17 1467

<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
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
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
> 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

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
> > > 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

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
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
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
* 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
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
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

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
> >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
> > > > > 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
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

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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

7
by: Michael Andersson | last post by:
Hi! Does the use of exception handling induce a performance penalty during the execution of non exception handling code? Regards, /Michael
9
by: Magalie | last post by:
Hi! I've got a question concerning C++ exceptions, more precisely the stack unwinding when an exception occurs. We agree that when an exception is thrown, all objects that have destructors are...
12
by: Siemel Naran | last post by:
(1) About std::exit. If I call this function, will the system call the destructors of all objects in the call stack. Eg. void f() { std::exit(1); } void g() { X x; f(); } Does the call in...
21
by: mihai | last post by:
People say that is a bad technique to throw exception from constructors; and that the solution would be to create a function _create_ to initialize an object. What about copy constructors? How...
59
by: kk_oop | last post by:
Hi. I wanted to use exceptions to handle error conditions in my code. I think doing that is useful, as it helps to separate "go" paths from error paths. However, a coding guideline has been...
15
by: Bernard | last post by:
Hi All, I am not sure if I should be asking this question on clc or clc++. Let me try on both. I hope that this is not too trivial for the brilliant minds over here. I know that OOP questions...
40
by: Mark P | last post by:
I'm implementing an algorithm and the computational flow is a somewhat deep. That is, fcn A makes many calls to fcn B which makes many calls to fcn C, and so on. The return value of the outermost...
42
by: Jon Harrop | last post by:
Why are exceptions in C++ ~6x slower than exceptions in OCaml? -- Dr Jon D Harrop, Flying Frog Consultancy Objective CAML for Scientists...
5
by: Rennie deGraaf | last post by:
I know that if an exception is thrown from a destructor while unwinding the stack because of another exception, terminate() is called (FAQ 17.3). How exactly does this rule work? Is it acceptable...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.