April 1st, 2021

C++ coroutines: What happens if an exception occurs in my return_value?

When I introduced a basic implementation of a promise type, I noted that the return_value method or return_void method is called when the coroutine performs a co_return. But what happens if the return_value or return_void method raises an exception?

void return_value(T const& v) const
{
    holder.set_result(v); // what if the copy constructor throws?
}

void unhandled_exception() const noexcept
{
    holder.set_exception(std::current_exception());
}

What if we take an exception trying to set the result, say because the copy constructor threw an exception? Do we have to catch the exception and convert it to a holder.set_exception?

void return_value(T const& v) const
{
    // Do I have to wrap the set_result?
    try {
        holder.set_result(v);
    } catch (...) {
        holder.set_exception(std::current_exception());
    }
}

Let’s go back and look at the transformation that the compiler performs when it generates a coroutine:

return_type MyCoroutine(args...)
{
    create coroutine state
    copy parameters to coroutine frame
    promise_type p;
    auto return_object = p.get_return_object();

    try {
        co_await p.initial_suspend(); // ¹
        coroutine function body
    } catch (...) {
        p.unhandled_exception();
    }
    co_await p.final_suspend();
    destruct promise p
    destruct parameters in coroutine frame
    destroy coroutine state
}

The return_value and return_void happen as part of the transformation of the co_return statement, and that is part of the section marked coroutine function body. Therefore, if an exception occurs during return_value or return_void, it is caught by the catch (...) and is delivered to unhandled_exception.

In other words, the compiler already wrapped your return_value and return_void functions inside a try/catch so you don’t have to.

Note however that there is no try/catch wrapped around the call to unhandled_exception, so that method should be careful not throw any exceptions.

Okay, so that was a brief digression on exceptions that occur when returning a value to the promise. Next time, we’ll look at another improvement to our coroutine promise implementation.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

0 comments

Discussion are closed.