Что происходит с локальными переменными при разматывании стека, на которые ссылается исключение? Рассмотрим следующий код:
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()
...
}
Что происходит с some_local_object? Разве он не должен быть уничтожен во время разматывания стека? Безопасно ли его использовать, как показано в примере?
Дополнительный вопрос
Как уже ответили, этот код приведет к неопределенному поведению. Мой второй вопрос к нему:
Если мне не разрешено передавать ссылку на локальный объект, и я не должен пытаться сделать его копию, потому что в редких случаях это может вызвать bad_alloc (поэтому, я думаю, стандартная библиотека gcc не имеет значимого сообщения об ошибке, то есть map.at генерирует исключение, для которого what () возвращает «map.at»), тогда какова хорошая стратегия для передачи дополнительной информации? Обратите внимание, что даже объединение нескольких строк во время построения сообщения об ошибке теоретически может вызвать bad_alloc. т.е .:
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
}
}
Поведение такое же, как и при возврате ссылки на переменную в стеке: объект уничтожается до того, как вы его используете. Таким образом, к тому времени, когда исключение перехватывается, ссылочный объект уничтожается, и любой доступ к ссылке приводит к неопределенному поведению.
Соответствующим пунктом в стандарте является пункт 15.2 [исключая.ctor]:
Когда управление переходит от точки, где исключение выдается обработчику, деструкторы вызываются для всех автоматических объектов, созданных с момента ввода блока try. Автоматические объекты уничтожаются в порядке, обратном завершению их строительства.
Локальный объект уничтожается при разматывании стека. Ссылка становится недействительной, свисающая ссылка. Это означает, что проверка объекта исключения, так что ссылка используется, будет иметь неопределенное поведение.