下面的代码生成 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;
}
}
}