9

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

 3 years ago
source link: https://devblogs.microsoft.com/oldnewthing/20210401-00/?p=105043
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

Raymond Chen

Raymond

April 1st, 2021

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.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK