简单的协程示例,每次都会崩溃

问题描述 投票:0回答:0

下面的代码生成 SIGSEGV,你能解释一下我在这里做错了什么吗?如果我调用 next() 正好 4 次,那么一切都可以,问题是如果我调用它第 5 次。我认为

T next() {
的实现有问题。我想要的是当协程到达 co_return 时抛出异常。

崩溃:

(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
  * frame #0: 0x0000000104e4f076 Coroutines1`std::__1::coroutine_handle<Generator<int>::promise_type>::resume[abi:v160006](this=0x00007ff7bb0b3140) const at coroutine_handle.h:169:9
    frame #1: 0x0000000104e4e2a0 Coroutines1`Generator<int>::next(this=0x00007ff7bb0b3140) at main.cpp:46:18
    frame #2: 0x0000000104e4e0b9 Coroutines1`main at main.cpp:69:30
    frame #3: 0x00007ff803436366 dyld`start + 1942

// https://godbolt.org/z/jGe8z3Yb5

#include <iostream>
#include <coroutine>
#include <vector>


template<typename T>
struct Generator {
    struct promise_type;
    using handle_type = std::coroutine_handle<promise_type>;

    struct promise_type {
        T value;
        std::suspend_always yield_value(T val) {
            value = val;
            return {};
        }
        std::suspend_never initial_suspend() { return {}; }
        std::suspend_never final_suspend() noexcept { return {}; }
        Generator get_return_object() { return Generator{handle_type::from_promise(*this)}; }
        void return_void() {}
        void unhandled_exception() { std::exit(1); }
        //void return_value(T val) {  }
    };

    handle_type coro;

    Generator(handle_type h): coro(h) {}
    ~Generator() {
        if (coro) {
            coro.destroy();
        }
    }
    Generator(const Generator&) = delete;
    Generator& operator=(const Generator&) = delete;
    Generator(Generator&& oth): coro(oth.coro) { oth.coro = nullptr; }
    Generator& operator=(Generator&& oth)  noexcept {
        if (this != &oth) {
            coro = oth.coro;
            oth.coro = nullptr;
        }
        return *this;
    }

    T next() {
        if (coro && !coro.done()) {
            coro.resume();
            if (!coro || coro.done())
                throw std::runtime_error("Generator has been fully consumed or does not exist.");
            return coro.promise().value;
        }
        throw std::runtime_error("Generator has been fully consumed or does not exist.");
    }

};

Generator<int> generator() {
    for (int i = 0; i < 5; ++i) {
        co_yield i;
    }
    co_return;
}

int main() {
    std::cout <<"Start!\n";
    auto gen = generator();

    while (true) {
        try {
            std::cout << gen.next() << '\n';
        }
        catch(std::runtime_error ex) {
            std::cout << ex.what() << "\n";
            break;
        }
    }
}
c++ c++-coroutine
© www.soinside.com 2019 - 2024. All rights reserved.