Сохранение исключения для последующего выбрасывания
Обычно когда ловится исключение оно либо сразу обрабатывается, либо бросается дальше. А вот можно ли делать так: сохранить указатель на объект исключения, выйти из блока catch, сделать ещё что-то, а потом бросить сохранённое исключение?
Другими словами, законен ли такой (работающий) код:
std::exception* SavedException = nullptr;
while(ThereIsSomethingToDo())
{
try {
DoSomething(); // Здесь может быть брошено исключение
}
catch(std::exception& e)
{
SavedException = &e;
// Продолжаем делать что-то, что должно быть сделано
}
}
// Всё, больше делать нечего
if(SavedException) throw *SavedException;
Понятно, что код требует доработки для случая, когда может быть брошено больше одного исключения, но мой вопрос не об этом. Может ли к моменту выполнения throw *SavedException испортиться объект исключения, на который указывает SavedException? До каких пор указателем на этот объект можно пользоваться?
Ответы (2 шт):
Вот так можно, если я верно понимаю, что вы хотите...
catch(std::exception& e)
{
// Продолжаем делать что-то, что должно быть сделано
throw; // Просто повторить исключение, которое обрабатываем, и отправить дальше
}
Если же вы хотите сгенерировать исключение после того, как закончите весь цикл — это чревато недоразумениями. Например, у вас было несколько исключений. Почему "регенерировать" именно последнее?
Update к вопросу, все ли будет в порядке...
Нет, не будет, сохранения нет. Это локальная переменная, которая уничтожается после обработки, т.е. вы получаете типичное UB.
Посмотрите сами на простой тестовый код:
#include <iostream>
#include <iomanip>
using namespace std;
class Ex
{
public:
Ex(){ cout << "ctor\n"; }
Ex(const Ex&){ cout << "cctor\n"; }
~Ex() { cout << "dtor\n"; }
};
int main(int argc, char * argv[])
{
for(int i = 0; i < 3; ++i)
{
try
{
throw Ex();
}
catch(Ex&e)
{
}
}
}
Видите? Исключения по окончании обработки просто нет...
Да, ваш указатель протухает. Используйте std::exception_ptr. Он работает примерно как shared_ptr для исключений:
std::exception_ptr saved_exception;
while (ThereIsSomethingToDo())
{
try
{
DoSomething();
}
catch (std::exception &e)
{
saved_exception = std::current_exception();
}
}
if (saved_exception)
std::rethrow_exception(saved_exception);