What happens to the local variables during stack unwinding, that are referenced in exception? Consider following code:
class bar;
class my_error
{
public:
my_error(const bar& bar) : _bar(bar) {}
const bar& get_bar() const { return _bar; }
private:
const bar& _bar;
}
...
bar some_local_object(...);
if (!foo()) {
throw my_error(some_local_object);
}
...
try {
g();
} catch (my_error& e) {
e.get_bar()
...
}
What happens to some_local_object? Shouldn't it be destroyed during stack unwinding? Is it safe to use it, as provided in example?
Additional question
As already answered, this code would lead to undefined behavior. My second question to it is:
If I am neither allowed to pass reference to local object nor should I try to make copy of it, because in rare case it could cause bad_alloc (which is why, I guess, gcc standard library has no meaningful error message, i.e. map.at throws exception for which what() returns "map.at"), then what is a good strategy to pass additional information? Note that even joining multiple strings, during construction of error message could theoretically cause bad_alloc. i.e.:
void do_something(const key& k, ....)
{
...
if (!foo(k)) {
std::ostringstream os;
os << "Key " << k << " not found"; // could throw bad_alloc
throw std::runtime_error(os.str());
}
// another approcach
if (!foo(k)) {
throw key_not_found(k); // also bad, because exception could outlive k
}
}
The behavior is the same as when returning a reference to a variable on the stack: the object is destroyed before you get to use it. That is, by the time the exception is caught, the referenced object is destroyed and all access to the reference result in undefined behavior.
The relevant clause in the standard is 15.2 [except.ctor] paragraph 1: