473,698 Members | 2,490 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Throw from a destructor

C++ers:

I have this friend who thinks C++ cannot throw from a destructor.

I think throwing from a destructor is bad Karma, and should be designed
around, but that C++ cannot strictly prevent the actual event.

(One compiler-oriented reason is a compiler might not be able to detect
that the call-tree from a destructor leads to a throw.)

Put another way, suppose I have a big object, aBigSimCity, and it has a
..shutdown() method. It must call before ~BigSimCity() calls, and it might
throw. This implies my Wrapper class, containing aBigSimCity, should never
declare a destructor like this: ~Wrapper() { aBigSimCity.shu tdown(); }.

..shutdown() might throw, and I don't feel like wrapping it in
try{}catch(). ~Wrapper should not throw, hence I need a better system to
break things down.

So which of us is right?

--
Phlip
Jul 7 '06 #1
17 3408
Phlip wrote:
I have this friend who thinks C++ cannot throw from a destructor.

I think throwing from a destructor is bad Karma, and should be designed
around, but that C++ cannot strictly prevent the actual event.

(One compiler-oriented reason is a compiler might not be able to detect
that the call-tree from a destructor leads to a throw.)

Put another way, suppose I have a big object, aBigSimCity, and it has a
.shutdown() method. It must call before ~BigSimCity() calls, and it might
throw. This implies my Wrapper class, containing aBigSimCity, should never
declare a destructor like this: ~Wrapper() { aBigSimCity.shu tdown(); }.

.shutdown() might throw, and I don't feel like wrapping it in
try{}catch(). ~Wrapper should not throw, hence I need a better system to
break things down.
Forgot to mention why this isn't a FAQ:

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

Suppose the Wrapper object contains a catch(...) that takes care of any
exceptions. So in this specific case, the Wrapper's destructor can
never be called during un-winding from a thrown exception, so its
destructor can always safely call things that might throw.

Don't do it anyway.

--
Phlip
Jul 7 '06 #2
Phlip wrote:
C++ers:

I have this friend who thinks C++ cannot throw from a destructor.

I think throwing from a destructor is bad Karma, and should be designed
around, but that C++ cannot strictly prevent the actual event.

(One compiler-oriented reason is a compiler might not be able to detect
that the call-tree from a destructor leads to a throw.)

Put another way, suppose I have a big object, aBigSimCity, and it has a
..shutdown() method. It must call before ~BigSimCity() calls, and it might
throw. This implies my Wrapper class, containing aBigSimCity, should never
declare a destructor like this: ~Wrapper() { aBigSimCity.shu tdown(); }.

..shutdown() might throw, and I don't feel like wrapping it in
try{}catch(). ~Wrapper should not throw, hence I need a better system to
break things down.

So which of us is right?
You!

I tend to add a throw() to my destructors (especially virtual) to
indicate that they will not throw.

--
Ian Collins.
Jul 7 '06 #3
Phlip wrote:
C++ers:

I have this friend who thinks C++ cannot throw from a destructor.

I think throwing from a destructor is bad Karma, and should be designed
around, but that C++ cannot strictly prevent the actual event.

(One compiler-oriented reason is a compiler might not be able to detect
that the call-tree from a destructor leads to a throw.)

Put another way, suppose I have a big object, aBigSimCity, and it has a
.shutdown() method. It must call before ~BigSimCity() calls, and it might
throw. This implies my Wrapper class, containing aBigSimCity, should never
declare a destructor like this: ~Wrapper() { aBigSimCity.shu tdown(); }.

.shutdown() might throw, and I don't feel like wrapping it in
try{}catch(). ~Wrapper should not throw, hence I need a better system to
break things down.

So which of us is right?
(Scott Meyer's Effective C++ 3rd edition, Item 8 addresses exactly this.)
How about something like (almost verbatim from the book):

class BigSimCity
{
void shutdown()
{
// do stuff that may throw
closed_ = true;
}
~BigSimCity() // would this have an empty throw() specification?
{
if (!closed)
{
try { shutdown(); }
catch (...) { // log or something }
}
}
private:
bool closed;
};

You give the client the chance to shutdown() on their own if they want
catch it on their own. And if not, then shutdown()'s called by the
destructor.

Joe
Jul 7 '06 #4

"Phlip" <ph*******@gEEE mail.comwrote in message
news:pa******** *************** *****@gEEEmail. com...
C++ers:

I have this friend who thinks C++ cannot throw from a destructor.

I think throwing from a destructor is bad Karma, and should be designed
around, but that C++ cannot strictly prevent the actual event.

(One compiler-oriented reason is a compiler might not be able to detect
that the call-tree from a destructor leads to a throw.)

Put another way, suppose I have a big object, aBigSimCity, and it has a
.shutdown() method. It must call before ~BigSimCity() calls, and it might
throw. This implies my Wrapper class, containing aBigSimCity, should never
declare a destructor like this: ~Wrapper() { aBigSimCity.shu tdown(); }.

.shutdown() might throw, and I don't feel like wrapping it in
try{}catch(). ~Wrapper should not throw, hence I need a better system to
break things down.

So which of us is right?

--
Phlip
There is nothing in the language to prevent a destructor from throwing. How
could the compiler enforce such a rule? Some of the other replies mention
using throw specifications but they don't help at all. Basically you should
never allow your destructor to throw. If ~BigSimCity() can throw the guy who
wrote it screwed up, not the client of the class.

Cy
Jul 7 '06 #5
On Fri, 7 Jul 2006 22:14:31 GMT, Joe Van Dyk <jo********@boe ing.com>
wrote:
>Phlip wrote:
>C++ers:
I have this friend who thinks C++ cannot throw from a destructor.
I think throwing from a destructor is bad Karma, and should be designed
around, but that C++ cannot strictly prevent the actual event.

(Scott Meyer's Effective C++ 3rd edition, Item 8 addresses exactly this.)
How about something like (almost verbatim from the book):

class BigSimCity
{
void shutdown()
{
// do stuff that may throw
closed_ = true;
}
~BigSimCity() // would this have an empty throw() specification?
{
if (!closed)
{
try { shutdown(); }
catch (...) { // log or something }
}
}
private:
bool closed;
};

You give the client the chance to shutdown() on their own if they want
catch it on their own. And if not, then shutdown()'s called by the
destructor.
The above works in some circumstances but is not a general solution.
It forces the client to write try-catch blocks, e.g.

try {
// ...
mySimCity.shutd own();
} catch (SimCityExcepti on& e) {
// do something
} catch (...) {
// do somethig else
}

In general, when the shutdown function produces meaningful output
(exception or return value) for the user it cannot be called in the
destructor.
Take as an example (good and bad) iostreams. When the file is opened
read-only then you can ignore the return value from close(). But when
the file is opened for write you cannot ignore the return value from
close(). Iostreams do not distinguish that cases and use the wrong
default.
Your example may be re-written in the following way:

class BigSimCity
{
bool commit()
{
// do stuff that may throw
closed_ = true;
return closed_;
}

void rollback() throw()
{
// do stuff that cannot throw or for which you
// can ignore exceptions and return values
}

~BigSimCity() throw()
{
if (!closed)
{
rollback();
}
}
private:
bool closed;
};

Best wishes,
Roland Pibinger
Jul 8 '06 #6
"Phlip" <ph*******@gEEE mail.comwrote in message
news:pa******** *************** *****@gEEEmail. com...
C++ers:

I have this friend who thinks C++ cannot throw from a destructor.

I think throwing from a destructor is bad Karma, and should be designed
around, but that C++ cannot strictly prevent the actual event.

(One compiler-oriented reason is a compiler might not be able to detect
that the call-tree from a destructor leads to a throw.)

Put another way, suppose I have a big object, aBigSimCity, and it has a
.shutdown() method. It must call before ~BigSimCity() calls, and it might
throw. This implies my Wrapper class, containing aBigSimCity, should never
declare a destructor like this: ~Wrapper() { aBigSimCity.shu tdown(); }.

.shutdown() might throw, and I don't feel like wrapping it in
try{}catch(). ~Wrapper should not throw, hence I need a better system to
break things down.

So which of us is right?
It's extremely simple to test. Just throw from a destructor and see if it's
allowed.

The answer is, yes, you can throw from a destructor but never ever should.
The problem being, as I understand it, if there are *2* errors thrown. The
compiler/OS can't handle this and terminates.
Jul 13 '06 #7
Jim Langston wrote:
It's extremely simple to test. Just throw from a destructor and see if
it's allowed.
Please don't mislead the newbies.

Newbies: Jim is teasing. You should never rely on your compiler's current
behavior to learn how C++ works. It may always compile more leniently than
the Standard, and its undefined behavior may appear to work correctly.

--
Phlip

Jul 13 '06 #8
Phlip wrote:
Jim Langston wrote:
>It's extremely simple to test. Just throw from a destructor and see if
it's allowed.

Please don't mislead the newbies.

Newbies: Jim is teasing. You should never rely on your compiler's current
behavior to learn how C++ works. It may always compile more leniently than
the Standard, and its undefined behavior may appear to work correctly.
Don't we know it! However, the Standard is usually as clear as mud and there are so
many cross-references it is very difficult to know whether the clause you're actually
reading is not modified by some other clause somewhere else (I've been bitten several
times by this - even if I have followed the cross-references and notes). Besides
this, some of the meanings of various concepts are not spelled out explicitly. For
instance I still can't find the specific definition of the term POD. I know what a
POD is (roughly) but I can't find a specific definition in the Standard other than a
note to say that the acronym POD stands for "Plain Old Data".

In answer to the OP, AFAIK the language doesn't _prevent_ throwing an exception from
a destructor but it should _never_ be done for at least two reasons that I know of:

1. Leaking an exception from a destructor during stack unwinding when processing an
exception leads to an immediate call to terminate - bang your dead! (to use Herb
Sutter's language).

2. If, for some reason, your lucky enough not to have terminate called, what do you
do with the exception when you've caught it? Re-throw if you can't recover? You're in
terminate land. In any case, how do you resuscitate or kill a partially dead object
when you have no way of knowing what state the object is in because that information
isn't conveyed to you by the exception class?

Sutter and others advise writing destructors as if they had an empty throw
specification. That's good enough for me! If you do specify it, say ~T() throw()
{...}, at least if an exception is leaked then terminate will be called immediately.
However, most people don't use throw specifications at all primarily because they're
expensive at runtime and sometimes they don't buy you very much in the way of safety
(Try analysing a piece of code and see how many exceptions it can possibly throw then
list these in the throw specifications. Can you do it consistently without any
errors? I know I can't.)

The meaning of undefined behaviour is a book in itself but broadly speaking it means
"anything is possible" from (seemingly) correct behaviour to your computer taking off
and launching itself into orbit or an invisible pink elephant suddenly appearing in
the room. Francis Glassborow relates a story in his recent book of how undefined
behaviour can bite and I once brought down a departmental server by missing out a 1
from the parameter list in a call to read() - took me 4 days to track down the
problem and I got a formal verbal warning for the mistake.

Anyway, that's my rant for the day!

Jim.
Jul 13 '06 #9

Jim Langston wrote:
It's extremely simple to test. Just throw from a destructor and see if it's
allowed.

The answer is, yes, you can throw from a destructor but never ever should.
The problem being, as I understand it, if there are *2* errors thrown. The
compiler/OS can't handle this and terminates.
There are numerous problems with destructors throwing, not the least of
which is:

class RandDestThrow
{
public:
~RandDestThrow( ) { if (!(rand() % 2)) throw 666; }
};

RandDestThrow * arr = new RandDestThrow[666];
try
{
delete [] arr;
} catch (...)
{
// What do we do exactly?
}

It is impossible to write exception safe code if any destructor can
throw. Destructors must therefore ALWAYS have the no-throw guarantee.
If this means having catch(...) then so be it...never allow exceptions
to escape a destructor...ne ver.

Jul 13 '06 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
1981
by: Eric Lilja | last post by:
Hello, in my program I have a function (pseudo code): void start_mysql_service() { obtain handle start mysql service using handle if start fails close handle and throw an exception containing error description
3
3494
by: Pierre Rouleau | last post by:
The std::exception class defined in the Standard C++ <exception> header specifies that the constructors could throw any exception becuase they do not have a throw() specification. Why is that? Is this because there could be an exception thrown when the code creates a std::exception? I would assume that is not the case. However, if I want to create a new exception class, derived from std::exception (say MyException) then how can I...
1
1378
by: qazmlp | last post by:
I have a class like this: class base { public: virtual ~base() throw(); // Other members }; Now, if I write a class like this:
3
1709
by: Shark | last post by:
I read that in the C++ standard library destructors are not supposed to throw exceptions. Is this true of only the library, or is it true of C++ classes in general?
5
1835
by: Kenneth Porter | last post by:
I've read this article and have some followup questions. http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thr ead/9d5324ce02f4d89b/ I'm working on an embedded robotics application that cannot terminate. I often have the need to temporarily change some setting before performing an operation. If the operation fails, I still need to restore the original setting. It's possible for the restore operation to fail
8
1988
by: Grizlyk | last post by:
Hello I want to understand the exception habdling in C++ more, because i think no one can apply anything free (free - without remembering large unclear list of rules and exceptions from rules and exceptions from exception from rules) if he does not understand "why" the thing have done excactly as is. I know, some people do not agree with me at the point of "why".
5
478
by: siddhu | last post by:
What happens when deletion falis?Does operator delete function throw exception? I assume that nothrow is not available with delete. Or is it available?
5
1874
by: stevewilliams2004 | last post by:
I was wondering if someone could explain the output I am getting for the program below. What I expected from the main program output was "Cat" but instead I see "Mammal". The output is also included below. I got the same results with GCC 3.4.4 under cygwin as with MSDev studio 2003. Even stranger to me, if I change the catch statement to catch a Cat instead of a Mammal, the program crashes in the catch body, during the call to...
28
3801
by: gnuist006 | last post by:
I have some code like this: (if (test) (exit) (do something)) or (if (test)
0
8685
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, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9171
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9032
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 tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
8880
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 protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
7743
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, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
6532
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
4373
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
2
2342
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2008
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.