使用协程在 C++ 中创建生成器

Create a generator in C++ using coroutines

根据McNellis对协程的介绍(Introduction to C Coroutines),我试着编译了一个简单协程的例子,其实就是一个简单的计数器。 然而,当 resume 被调用时,断言被触发。 具体

_LIBCPP_ASSERT(!done(), "resume() has undefined behaviour when the coroutine is done");

我对协程的经验不多,我找不到问题所在。

代码如下

#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;
}

请查找代码here

promise_type::get_return_object() 应 return 用户定义协程结果类型 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)) {}
    // ...
};

并且 resumable_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;
    }