首页 > 解决方案 > 使用协程在 C++ 中创建生成器

问题描述

继 McNellis 对协程的介绍(Introduction to C Coroutines)之后,我尝试编译简单协程的示例,它实际上是一个简单的计数器。但是,当调用 resume 时,会触发断言。具体来说

_LIBCPP_ASSERT(!done(), "resume() 在协程完成时有未定义的行为");

我对协程没有太多经验,我无法找出问题所在。

代码如下

#include <iostream>
#include <coroutine>

using namespace std;
//using namespace experimental;
struct resumable_thing
{
    struct promise_type
    {
            int const* _current;
            promise_type & get_return_object() noexcept
            {
                return *this;
            }
            auto initial_suspend() { return suspend_always{}; }
            auto final_suspend() { return suspend_always{}; }
            auto yield_value(int const& value) {
                _current = &value;
                return suspend_always{};
            }
            void unhandled_exception()
            {
                auto ex = std::current_exception();
                std::rethrow_exception(ex);
                //// MSVC bug? should be possible to rethrow with "throw;"
                //// rethrow exception immediately
                // throw;
            }
            void return_void() noexcept
            {
            }
    };
   // using coroutine_handle = coroutine_handle<promise_type>;
    resumable_thing() = default;
    resumable_thing(resumable_thing const &  ) = delete;
    resumable_thing & operator = (resumable_thing const &  ) =delete;
    resumable_thing(promise_type && promise)
            : _coroutine(coroutine_handle<promise_type>::from_promise(promise)) {}
    resumable_thing(resumable_thing&& other) : _coroutine(other._coroutine)
    {
            other._coroutine = nullptr;
    }
    resumable_thing & operator = (resumable_thing const &&  other)
    {
        _coroutine = other._coroutine;
        _coroutine = nullptr;
        return *this;
    }
    explicit resumable_thing(coroutine_handle<promise_type> coroutine)
    :_coroutine(coroutine)
    {
        
    }
    ~resumable_thing()
    {
        if(_coroutine)
        {
            _coroutine.destroy();
        }
    }
    void resume()
    {
        std::cout << "coroutines resume" << std::endl;
        _coroutine.resume();
        
    }
    coroutine_handle<promise_type> _coroutine = nullptr;
    
    
};

resumable_thing counter()
{
    cout << "counter: called\n";
    for(int i = 0 ; ++i;)
    {
        co_await suspend_always{};
        cout << "counter: resumed (#" << i << ")\n";
    }
}
int main(int argc, const char * argv[]) {
    // insert code here...
    cout << "main:    calling counter\n";
    resumable_thing the_counter = counter();
    cout << "main:    resuming counter\n";
    the_counter.resume();//assertion is fired
    cout << "main:done" << std::endl;
    return 0;
}

请在此处找到代码

标签: c++c++20c++-coroutine

解决方案


promise_type::get_return_object()应返回用户定义的协程结果类型resumable_thing,而不是promise_type&自身。

struct resumable_thing
{
    struct promise_type
    {
         resumable_thing get_return_object() noexcept
         {
             return {*this};
         }
         // ...
    };
    resumable_thing(promise_type & promise)
        : _coroutine(coroutine_handle<promise_type>::from_promise(promise)) {}
    // ...
};

Andresumable_thing的移动赋值运算符this->_coroutine无意中重置。

    // FIXED: resumable_thing const && -> resumable_thing &&
    resumable_thing & operator = (resumable_thing && other)
    {
        _coroutine = other._coroutine;
        // FIXED: _coroutine -> other._coroutine
        other._coroutine = nullptr;
        return *this;
    }

推荐阅读