C++ 协程和 const 引用参数

imr*_*eal 2 c++ temporary-objects c++20 c++-coroutine

来自注释3https://eel.is/c++draft/dcl.fct.def.coroutine#13中的

\n
\n

[注3:\xe2\x80\x82如果协程具有通过引用传递的参数,则在该参数引用的实体的生命周期结束后恢复协程可能会导致未定义的行为。\xe2\x80\x94 尾注]

\n
\n

很明显,如果粗心的调用者不能确保提供的参数比协程对象寿命更长,那么在协程中通过引用获取参数可能会导致未定义的行为。

\n

但是用临时变量初始化的 const 引用参数又如何呢?如果标准保证参数的生命周期由本地引用延长,这对我来说是有意义的,但我找不到任何相关信息。

\n

这是定义的行为吗(假设 coro() 在第一次暂停后使用 obj ),如果是,它是什么?

\n
task<void> coro(const Obj& obj);\n\n...\n\nauto tsk = coro(Obj{});\nco_await tsk;\n
Run Code Online (Sandbox Code Playgroud)\n

在我看来,如果不允许这样做,则 const 引用根本不能用作协程参数,因为有人传递临时值并假设普通函数行为的风险。

\n

Nic*_*las 5

很明显,如果粗心的调用者不能确保提供的参数比协程对象寿命更长,那么在协程中通过引用获取参数可能会导致未定义的行为。

但是用临时变量初始化的 const 引用参数又如何呢?

这就是“粗心的调用者”的定义,“不确保提供的参数比协程对象的寿命更长”。在这种情况下没有特殊规定。用作函数参数的临时变量的生命周期将扩展到包含函数调用的完整表达式的生命周期。该函数调用作为协程不会改变这一点。

请记住:作为协程是函数的实现细节。调用者(具有临时函数的调用者)不知道函数是否是协程。所以不仅没有特殊规定,而且也不可能有特殊规定。

在我看来,如果不允许这样做,则 const 引用根本不能用作协程参数,因为有人传递临时值并假设普通函数行为的风险。

C++ 的一般设计方式假设用户知道他们在做什么。只要可以以非危险的方式使用该东西,该语言经常不会阻止您做危险的事情。

话虽如此,如果需要,协程函数本身可以简单地在内部将任何此类参数复制到其堆栈中。协程可以设置为最初不挂起,这保证了它将执行到第一个显式挂起点。届时,他们可以采取任何措施来确保使用安全。也许该函数在第一个暂停点之后永远不会使用该参数。也许还有别的东西。

因此,您的示例可能有 UB,也可能没有,具体取决于协程内部发生的情况。