Mik*_*Lui 8 c++ language-lawyer c++20 c++-coroutine
这个问题源于这个评论:C++20 协程的 Lambda 生命周期解释
关于这个例子:
auto foo() -> folly::coro::Task<int> {
auto task = []() -> folly::coro::Task<int> {
co_return 1;
}();
return task;
}
Run Code Online (Sandbox Code Playgroud)
所以问题是执行返回的协程是否foo会导致UB。
“调用”成员函数(在对象的生命周期结束后)是 UB:http : //eel.is/c++draft/basic.life#6.2
...任何表示对象将位于或曾经位于的存储位置地址的指针都可以使用,但只能以有限的方式使用。[...] 程序有未定义的行为,如果:
[...]
-- 指针用于访问非静态数据成员或调用对象的非静态成员函数,或
但是,在这个例子中:
()lambda 的生命周期仍然有效时调用 lambda的运算符())在之后的某个时间点恢复。此恢复是否被视为未定义行为?
协程的 Promise类型为
std::coroutine_traits<R, P1, ..., Pn>::promise_type,其中R是函数的返回类型,P1 ... Pn是函数参数的类型序列, 如果协程是非静态的,则前面是隐式对象参数的类型(12.4.1)成员函数。
在您的示例中,隐式对象参数是一个常量引用,因此当闭包对象被销毁后恢复执行时,该引用将悬空。
然而,注意在执行成员函数期间对象被销毁,这本身确实很好,并且标准本身在[basic]中暗示了这一点:
在对象的生命周期开始之前,但在该对象将占用的存储空间已分配之后,或者在对象的生命周期结束之后,在重用或释放该对象所占用的存储空间之前,任何表示该对象的地址的指针可以使用该对象将要或曾经位于的存储位置,但只能以有限的方式使用。[...]
Run Code Online (Sandbox Code Playgroud)void B::mutate() { new (this) D2; // reuses storage --- ends the lifetime of *this f(); // undefined behavior ... = this; // OK, this points to valid memory }
(注:上面的UB是因为隐式this没有被洗白,仍然指的是隐式对象参数。)
因此,您的示例似乎定义良好,条件是恢复执行不属于与原始调用相同的规则。请注意,对闭包对象的引用可能是悬空的,但在挂起和恢复之间不会以任何方式访问它。