If a catch block cannot handle the particular exception it has caught, we can rethrow the exception. The rethrow expression causes the originally thrown object to be rethrown.
If a catch block cannot handle the particular exception it has caught, you can rethrow the exception. The rethrow expression ( throw without assignment_expression) causes the originally thrown object to be rethrown.
Re-throwing an exception means calling the throw statement without an exception object, inside a catch block. It can only be used inside a catch block.
A Throw statement with no expression can only be used in a Catch statement, in which case the statement rethrows the exception currently being handled by the Catch statement. The Throw statement resets the call stack for the expression exception.
In both cases, since you catch by reference, you are effectively altering the state of the original exception object (which you can think of as residing in a magical memory location which will stay valid during the subsequent unwinding -- 0x98e7058
in the example below). However,
throw;
(which, unlike throw err;
, preserves the original exception object, with your modifications, in said "magical location" at 0x98e7058
) will reflect the call to append()
err
will be created then thrown anew (at a different "magical location" 0x98e70b0
-- because for all the compiler knows err
could be an object on the stack about to be unwinded, like e
was at 0xbfbce430
, not in the "magical location" at 0x98e7058
), so you will lose derived-class-specific data during the copy-construction of a base class instance.Simple program to illustrate what's happening:
#include <stdio.h>
struct MyErr {
MyErr() {
printf(" Base default constructor, this=%p\n", this);
}
MyErr(const MyErr& other) {
printf(" Base copy-constructor, this=%p from that=%p\n", this, &other);
}
virtual ~MyErr() {
printf(" Base destructor, this=%p\n", this);
}
};
struct MyErrDerived : public MyErr {
MyErrDerived() {
printf(" Derived default constructor, this=%p\n", this);
}
MyErrDerived(const MyErrDerived& other) {
printf(" Derived copy-constructor, this=%p from that=%p\n", this, &other);
}
virtual ~MyErrDerived() {
printf(" Derived destructor, this=%p\n", this);
}
};
int main() {
try {
try {
MyErrDerived e;
throw e;
} catch (MyErr& err) {
printf("A Inner catch, &err=%p\n", &err);
throw;
}
} catch (MyErr& err) {
printf("A Outer catch, &err=%p\n", &err);
}
printf("---\n");
try {
try {
MyErrDerived e;
throw e;
} catch (MyErr& err) {
printf("B Inner catch, &err=%p\n", &err);
throw err;
}
} catch (MyErr& err) {
printf("B Outer catch, &err=%p\n", &err);
}
return 0;
}
Result:
Base default constructor, this=0xbfbce430
Derived default constructor, this=0xbfbce430
Base default constructor, this=0x98e7058
Derived copy-constructor, this=0x98e7058 from that=0xbfbce430
Derived destructor, this=0xbfbce430
Base destructor, this=0xbfbce430
A Inner catch, &err=0x98e7058
A Outer catch, &err=0x98e7058
Derived destructor, this=0x98e7058
Base destructor, this=0x98e7058
---
Base default constructor, this=0xbfbce430
Derived default constructor, this=0xbfbce430
Base default constructor, this=0x98e7058
Derived copy-constructor, this=0x98e7058 from that=0xbfbce430
Derived destructor, this=0xbfbce430
Base destructor, this=0xbfbce430
B Inner catch, &err=0x98e7058
Base copy-constructor, this=0x98e70b0 from that=0x98e7058
Derived destructor, this=0x98e7058
Base destructor, this=0x98e7058
B Outer catch, &err=0x98e70b0
Base destructor, this=0x98e70b0
Also see:
This question is rather old and has an answer appropriate to the time it was asked. However, I just want to add a note on how to do proper exception handling since C++11 and I believe this corresponds very well to what you were trying to achieve with your append function:
std::nested_exception
and std::throw_with_nested
It is described on StackOverflow here and here, how you can get a backtrace on your exceptions inside your code without need for a debugger or cumbersome logging, by simply writing a proper exception handler which will rethrow nested exceptions.
Since you can do this with any derived exception class, you can add a lot of information to such a backtrace! You may also take a look at my MWE on GitHub, where a backtrace would look something like this:
Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
Yes, rethrowing rethrows the original exception object, which you have modified by a reference. You can also catch a base class reference, modify by it and still be able to rethrow the original derived exception type by throw;
.
for first question, yes.
but for second, refer to Vlad answer. you will need to carefully design your exception object to handle copy ctor. by convention, base class doesn't recognize its child so you will most likely lose the additional data carried by derived class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With