从 promise_type 获取 return 值的最佳方法是什么
What is the best way to return value from promise_type
我对 C++20 中的协程有点卡住了。我尝试创建一个异步任务:
template <typename T>
struct Task {
public:
struct promise_type {
using Handle = std::coroutine_handle<promise_type>;
promise_type() = default;
~promise_type() = default;
Task get_return_object() { return Task{Handle::from_promise(*this)}; }
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_value(T val) noexcept { value_ = val; }
void unhandled_exception() { std::cout << "Unhandled exception in coroutine\n"; }
T value_;
};
explicit Task(typename promise_type::Handle coro) : coro_(coro) {}
std::optional<T> Get() {
return coro_.done() ?
std::make_optional(coro_.promise().value_) : std::nullopt;
}
private:
typename promise_type::Handle coro_;
};
虚拟用法示例:
Task<int> Coro() {
co_await std::suspend_never();
co_return 1;
}
int main() {
auto task = Coro();
std::cout << *task.Get();
return 0;
}
问题出在Task::Get()
方法中。当我试图从 promise_type
中获取一个值时,它已经被销毁了。我试图用指针连接 Task 和 promise_type,但它看起来有点难看。我相信对此有一些标准和简单的方法。
更新:
只有在协程未挂起时才会发生这种情况。在这种情况下,promise_type 在调用 Get() 之前被销毁。
我自己也在学习协程,但我相信解决这个问题的方法是改变 Task
的销毁方式。
目前,您有 final_suspend
return std::suspend_never
。所以控制 returns 立即到调用者 (main
) 并且 promise
被销毁。在那种情况下,你必须做这样的事情:
I'm trying to connect Task and promise_type with a pointer, but it looks a bit ugly
基本上这样 promise
就可以将其 return_value
写入 Task
.
但我们可以做一些不同的事情。您可以始终暂停:
std::suspend_always final_suspend() noexcept { return {}; }
并确保 Task
本身销毁协程:
~Task() {
if (coro_) coro_.destroy();
}
这样,promise
在 task
被销毁之前不会被销毁,这意味着 task.Get()
不会访问悬空的...协程。你可以看到差异 here.
我对 C++20 中的协程有点卡住了。我尝试创建一个异步任务:
template <typename T>
struct Task {
public:
struct promise_type {
using Handle = std::coroutine_handle<promise_type>;
promise_type() = default;
~promise_type() = default;
Task get_return_object() { return Task{Handle::from_promise(*this)}; }
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept { return {}; }
void return_value(T val) noexcept { value_ = val; }
void unhandled_exception() { std::cout << "Unhandled exception in coroutine\n"; }
T value_;
};
explicit Task(typename promise_type::Handle coro) : coro_(coro) {}
std::optional<T> Get() {
return coro_.done() ?
std::make_optional(coro_.promise().value_) : std::nullopt;
}
private:
typename promise_type::Handle coro_;
};
虚拟用法示例:
Task<int> Coro() {
co_await std::suspend_never();
co_return 1;
}
int main() {
auto task = Coro();
std::cout << *task.Get();
return 0;
}
问题出在Task::Get()
方法中。当我试图从 promise_type
中获取一个值时,它已经被销毁了。我试图用指针连接 Task 和 promise_type,但它看起来有点难看。我相信对此有一些标准和简单的方法。
更新:
只有在协程未挂起时才会发生这种情况。在这种情况下,promise_type 在调用 Get() 之前被销毁。
我自己也在学习协程,但我相信解决这个问题的方法是改变 Task
的销毁方式。
目前,您有 final_suspend
return std::suspend_never
。所以控制 returns 立即到调用者 (main
) 并且 promise
被销毁。在那种情况下,你必须做这样的事情:
I'm trying to connect Task and promise_type with a pointer, but it looks a bit ugly
基本上这样 promise
就可以将其 return_value
写入 Task
.
但我们可以做一些不同的事情。您可以始终暂停:
std::suspend_always final_suspend() noexcept { return {}; }
并确保 Task
本身销毁协程:
~Task() {
if (coro_) coro_.destroy();
}
这样,promise
在 task
被销毁之前不会被销毁,这意味着 task.Get()
不会访问悬空的...协程。你可以看到差异 here.