Topic: Handling exceptions from implicitly-called functions
Author: Scott Meyers <smeyers@netcom.com>
Date: 1997/03/12 Raw View
I have a few questions about the context in which certain exceptions are
thrown and where they may be handled.
What is the context for an exception thrown during construction of a
function parameter or return value? Consider:
class Widget {
public:
Widget(int);
Widget(const Widget&);
};
Widget makeAWidget(Widget w) // makeAWidget takes and returns
try { return 1; } catch(...) {} // a Widget by value; it also has
// a function try block handling
// every type of exception
a) Suppose an exception is thrown during construction of the
parameter w. Is the exception handled by makeAWidget's function
try block?
Widget x(1);
makeAWidget(x); // if Widget::Widget(const Widget&)
// throws, does makeAWidget's try block
// handle it?
b) Does the answer change if the exception is thrown during type
conversion from the type of the actual parameter to the type
of the formal? For example:
makeAWidget(1); // 1 must be converted to Widget to make
// the call succeed; if Widget::Widget(int)
// throws (prior to the call to Widget's copy
// constructor to copy the temporary over to
// w), does makeAWidget's try block handle
// the exception?
c) Same as (a), but for makeAWidget's return value:
Widget makeAWidget(Widget w) // if an exception is thrown
try { return w; } catch(...) {} // during construction of the
// return value from w, does
// makeAWidget's function try
// block handle it?
d) Same as (b), but for makeAWidget's return value:
Widget makeAWidget(Widget w) // if an exception is thrown
try { return 1; } catch(...) {} // during construction of the
// temporary Widget from 1 or
// the copying of the temporary
// to the return value, does
// makeAWidget's function try
// block handle it?
On a sort-of-related topic, can function try blocks of constructors and
destructors handle exceptions thrown during construction and
destruction, respectively, of member subobjects? For example:
class Widget {
private:
Thingie t; // Thingie is just some random class
public:
Widget() try {} catch(...) {} // if t's constructor throws, is it
// handled by the Widget constructor's
// function try block handler?
~Widget() try {} catch(...) {} // if t's destructor throws, is it
// handled by the Widget destructor's
// function try block handler?
I know I've read somewhere that the answer to the last two questions is
yes, but tonight I read through section 15 ("Exception Handling") of
the 12/96 WP, and I can't find any wording to that effect. In fact,
15.3/11 seems to suggest that destruction of subobjects has already run
to completion by the time a function try block's handler is entered:
11 The fully constructed base classes and members of an object shall be
destroyed before entering the handler of a function-try-block of a
constructor or destructor for that object.
I'd really appreciate any clarification you can provide for this issue,
ideally along with pointers to relevant CD sections.
Thanks,
Scott
----------------------------------------------------------------------------
Scott Meyers, Ph.D. Voice: 503/638-6028
Software Development Consultant Fax: 503/638-6614
3051 SW Turner Road Email: smeyers@netcom.com
West Linn, Oregon 97068 WWW: http://www.teleport.com/~smeyers
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]
Author: fjh@murlibobo.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/03/12 Raw View
Scott Meyers <smeyers@netcom.com> writes:
>On a sort-of-related topic, can function try blocks of constructors and
>destructors handle exceptions thrown during construction and
>destruction, respectively, of member subobjects?
Yes. However, admittedly the draft is not very clear about this.
The strongest evidence is 15.1[except.throw]/2, combined with
15[except]/3. Here's the former:
| 15.1 Throwing an exception [except.throw]
|
| 2 When an exception is thrown, control is transferred to the nearest
| handler with a matching type (_except.handle_); "nearest" means the
| handler whose try block was most recently entered by the thread of
| control and not yet exited.
This sort of begs the question, what is the sequence followed by the
thread of control? Does the thread of control enter the function-try-block
before executing the constructors, or does it execute the constructors
first? The next quote helps us answer this question:
|15 Exception handling [except]
[...]
| 3 A function-try-block associates a handler-seq with the ctor-initial-
| izer, if present, and the function-body. An exception thrown during
| the execution of the initializer expressions in the ctor-initializer
| or during the execution of the function-body transfers control to a
| handler in a function-try-block in the same way as an exception thrown
| during the execution of a try-block transfers control to other han-
| dlers.
Since the ctor-initializer must be executed before the constructors of
members or bases can be executed, the thread of control must enter the
function-try-block before those constructors start. You can also
presume that the corresponding destructors are executed before the
thread of control leaves the function-try-block (see below).
I suppose that if one were trying to interpret the draft perversely,
one could imagine scenarios where the sequence followed by the thread
of control differs depending on whether or not there is a
ctor-initializer, or where the thread of control exits and re-enters a
function-try-block but I'm sure that isn't the intent.
>I know I've read somewhere that the answer to the last two questions is
>yes, but tonight I read through section 15 ("Exception Handling") of
>the 12/96 WP, and I can't find any wording to that effect. In fact,
>15.3/11 seems to suggest that destruction of subobjects has already run
>to completion by the time a function try block's handler is entered:
>
> 11 The fully constructed base classes and members of an object shall be
> destroyed before entering the handler of a function-try-block of a
> constructor or destructor for that object.
The above quote is the evidence needed to show that the thread of
control doesn't leave the function-try-block before executing the
destructors of sub-objects, because it says that the latter must
be executed before the former. It also implies that if a destructor
for a sub-object throws an exception, then the implementation must, in
the process of stack unwinding, call the destructors for the remaining
sub-objects before entering the function-try-block.
--
Fergus Henderson <fjh@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3 | -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu ]