Сохранение исключения для последующего выбрасывания

Обычно когда ловится исключение оно либо сразу обрабатывается, либо бросается дальше. А вот можно ли делать так: сохранить указатель на объект исключения, выйти из блока catch, сделать ещё что-то, а потом бросить сохранённое исключение?

Другими словами, законен ли такой (работающий) код:

std::exception* SavedException = nullptr;
while(ThereIsSomethingToDo())
{
    try {
        DoSomething(); // Здесь может быть брошено исключение
    }
    catch(std::exception& e)
    {
        SavedException = &e;
            // Продолжаем делать что-то, что должно быть сделано
    }
}
    // Всё, больше делать нечего
if(SavedException) throw *SavedException;

Понятно, что код требует доработки для случая, когда может быть брошено больше одного исключения, но мой вопрос не об этом. Может ли к моменту выполнения throw *SavedException испортиться объект исключения, на который указывает SavedException? До каких пор указателем на этот объект можно пользоваться?


Ответы (2 шт):

Автор решения: Harry

Вот так можно, если я верно понимаю, что вы хотите...

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)
        {
        }
    }
}

Видите? Исключения по окончании обработки просто нет...

→ Ссылка
Автор решения: HolyBlackCat

Да, ваш указатель протухает. Используйте 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);
→ Ссылка