Daily bit(e) C++. std::current_exception, std::exception_ptr, std::rethrow_exception

Добавлено 14 сентября 2026 в 04:08

Daily bit(e) C++ 106, использование механизмов сохранения и повторного выброса исключений (появившихся в C++11) при реализации корутин.

Daily bit(e) C++

При реализации корутин необходимо решить, как именно обрабатывать исключения.

Один из вариантов – игнорировать исключения и завершить выполнение программы методом unhandled_exception().

В качестве альтернативы можно воспользоваться механизмами сохранения и повторного выброса исключений, доступными в C++11:

  • std::current_exception
  • std::exception_ptr
  • std::rethrow_exception
#include <iostream>
#include <coroutine>
#include <exception>

template <typename Result>
struct Promise;

// Тип результата
template <typename Result>
struct Task : std::coroutine_handle<Promise<Result>> 
{
    using promise_type = Promise<Result>;

    ~Task() 
    { 
        this->destroy(); 
    }
    
    Result& get_value() 
    {
        // если корутина завершилась исключением,
        // выбросить исключение повторно
        if (this->promise().exception_)
            std::rethrow_exception(this->promise().exception_);
        // иначе, вернуть результат
        return this->promise().value_;
    }
};

// Тип промис
template <typename Result>
struct Promise 
{
    Task<Result> get_return_object() 
    { 
        return {Task<Result>::from_promise(*this)}; 
    }
    std::suspend_always initial_suspend() noexcept 
    {
        return {}; 
    }
    std::suspend_always final_suspend() noexcept 
    {
        return {}; 
    }

    void return_value(auto&& val) 
    {   // сохранить результат
        value_ = std::forward<decltype(val)>(val);
    }
    void unhandled_exception() 
    {   // сохранить исключение
        exception_ = std::current_exception();
    }
    
    Result value_;
    std::exception_ptr exception_;
};

Task<int> coro_success() 
{
    co_return 1;
}

Task<int> coro_throws() 
{
    throw std::runtime_error("Failed.");
    co_return 2;
}


try 
{
    auto c1 = coro_success();
    c1.resume(); // дать корутине выполниться
    std::cout << c1.get_value() << "\n";
    // напечатает "1"  

    auto c2 = coro_throws();
    c2.resume(); // дать корутине выполниться
    std::cout << c2.get_value() << "\n";
    // c2.get_value() повторно выбрасывает исключение
} 
catch (const std::exception& e) 
{
    // e.what() == "Failed."
    std::cout << e.what() << "\n";
}

Пример на Compiler Explorer

Теги

C++ / CppCoroutine / КорутинаDaily bit(e) C++Программирование