Re: What are the general and C++0x guidelines for writing exceptions?
On 2 Mai, 14:52, DeMarcus <use_my_alias_h...@hotmail.com> wrote:
Hi,
In C++ Coding Standards by Sutter & Alexandrescu, Item 32, they say in short; "An exception class has no-fail constructors,
especially a no-fail copy constructor".
I have some thoughts regarding this.
1. An exception class doesn't /need/ to have no-fail constructor, right? It's just that the following
throw SomeException();
might actually throw std::bad_alloc instead if the constructor tried to allocate something and the memory is out.
Correct me if I'm wrong, but allowing the constructor to throw will not introduce inconsistency or undefined behavior. It will
just uncontrollable change the attention to std::bad_alloc that took precedence, so the biggest problem is that the original
exception won't be logged. Or are there any other implications by throwing from the exception constructor?
This question is not an easy one. The crux of the matter is
the current wording of [except.terminate]/1 b. 1:
"In the following situations exception handling must be
abandoned for less subtle error handling techniques:
? when the exception handling mechanism, after completing
evaluation of the expression to be thrown but before the
exception is caught (15.1), calls a function that exits
via an uncaught exception, (footnote 143)"
with footnote 143:
"For example, if the object being thrown is of a class
with a copy constructor, std::terminate() will be called
if that copy constructor exits with an exception during
a throw."
So there exists some reason to assume that an exception
thrown during the evaluation of the throw expression
shall invoke terminate.
But this conclusion depends indirectly on the question
when the function std::uncaught_exception() evaluates to
true and there exists a lengthy issue about this problem:
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#475
This discussion shows that the wording needs to be clearer
and that current implementations vary. As of the currently
proposed resolution it looks like as if the wanted outcome
should be that your example would not invoke terminate,
but instead would throw the exception of the copy constructor.
According to this wording, there would still be chance to
get std::terminate involved, but this could only happen,
if the programmer defines an exception handler "by-value":
void test() {
try {
throw SomeException(); // #1
} catch (SomeException) { // #2
}
}
int main() {
try {
test();
} catch(...) {
}
}
Assume that the copy constructor or default constructor
involved in #1 does *not* throw an exception, but the
copy constructor involved in #2 does, this will still
lead to an invokation of std::terminate according to
the current P/R of #475. IMO this is acceptable, because
most style guide's I'm aware of already require that
exceptions should be caught by reference, so this
should be not a typical problem.
2. I understand that an exception class must have a no-fail copy constructor if I catch by value, but why do I need to have a copy
constructor at all if I catch by reference?
Because the runtime needs to create the so-called
exception object, see [except.throw]/3+4, which is
a copy of the initial-exception. This special exception
object cannot be an automatic object, because it's
life-time will need to exceed the current scope.
It is explicitly allowed for an implementation to
elide the copy step in your example, but that is
not a requirement, see [except.throw]/5:
"When the thrown object is a class object, the copy/move
constructor and the destructor shall be accessible,
even if the copy/move operation is elided (12.8)."
3. Will C++0x be able to utilize the move semantics to
avoid all copy construction of exceptions?
Yes, an implementation is allowed to call the move
constructor, if such exists. This is one of the
special cases listed in [class.copy]/34 bullet 2:
"? in a throw-expression, when the operand is the
name of a non-volatile automatic object whose scope
does not extend beyond the end of the innermost
enclosing try-block (if there is one), the copy/move
operation from the operand to the exception object
(15.1) can be omitted by constructing the automatic
object directly into the exception object"
But the currently considered P/R of 475 would also
ensure this for the general case.
HTH & Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]