#include <iostream>
#include <experimental/coroutine>
#include <string>
#include <thread>
struct InitialSuspend{
bool await_ready(){
return false;
}
bool await_suspend(std::experimental::coroutine_handle<> h){
return false;
}
void await_resume(){
}
};
struct FinalSuspend{
bool await_ready() noexcept{
return false;
}
void await_suspend(std::experimental::coroutine_handle<> h) noexcept{
std::cout<<"FinalSuspend await_suspend\n";
}
std::string await_resume() noexcept{
std::cout<< "await_resume for FinalSuspend\n";
return "await_resume for FinalSuspend\n";
}
};
struct Task{
struct promise_type;
using coroutine_type = std::experimental::coroutine_handle<promise_type>;
struct promise_type{
auto initial_suspend(){
return InitialSuspend{};
}
void unhandled_exception(){
std::cout<<"unhandled_exception\n";
std::terminate();
}
auto final_suspend() noexcept{
return FinalSuspend{};
}
// void return_value(std::string const& v){
// value_ = v;
// }
void return_void(){
}
auto get_return_object(){
return Task{coroutine_type::from_promise(*this)};
}
std::string value_;
};
coroutine_type handler_;
};
struct AwaitAble{
bool await_ready(){
return false;
}
void await_suspend(std::experimental::coroutine_handle<> h){
std::cout<<"await_suspend\n";
}
std::string await_resume(){
std::cout<<"await_resume\n";
return "abc";
}
};
struct Observe0{
Observe0(int v):id_(v){
std::cout<< id_ <<" constructor0\n";
}
~Observe0(){
std::cout<< id_ <<" destroy0\n";
}
Observe0(Observe0 const& v):id_(v.id_+1){
std::cout<< id_<<" copy constructor0\n";
}
Observe0(Observe0&& v):id_(v.id_+1){
std::cout<< id_<<" move constructor0\n";
}
int id_;
};
Task MyCoroutine(Observe0 p){
auto r1 = co_await AwaitAble{};
}
int main(){
Observe0 aa{1}; //#1
auto r = MyCoroutine(aa); //#2
std::cout<<"caller\n";
r.handler_.resume();
r.handler_.destroy();
std::cin.get();
}
输出结果为:output
1 constructor0
2 copy constructor0
3 move constructor0
await_suspend
2 destroy0
caller
await_resume
FinalSuspend await_suspend
3 destroy0
1 destroy0
使用上述代码,我们可以观察对象的创建或销毁。第一次打印发生在
#1
处,它构造了对象a
。第二次打印发生在协程参数的初始化时,在#2
处。第三个打印是在协程参数副本的初始化时发生的,其受以下规则控制:[dcl.fct.def.coroutine#13] 引用如下:
这三个对象都有其独特的数字,方便观察相关对象的生命周期。根据第五个打印输出,析构函数被调用的是名为调用协程后,在初始化其参数([expr.call])之后,为每个协程参数创建一个副本。对于类型为cv T的参数,该副本是具有自动存储期的cv T类型变量,该变量从引用参数的T类型的xvalue进行直接初始化。
p
的协程参数。然而,根据[expr.await#5.1]:引用如下:
这意味着挂起协程并将控制传输给调用者时,协程参数的作用域并未被认为已经退出。因此,参数的生命周期不应该结束。那么为什么在第一次转移到协程的调用者后调用参数的析构函数?这是编译器中的漏洞吗?否则,控制流返回到当前协程调用者或恢复器([dcl.fct.def.coroutine]),不会退出任何作用域([stmt.jump])。