【问题标题】:When do temporaries passed to coroutines get destroyed?传递给协程的临时对象何时被销毁?
【发布时间】:2019-08-19 12:46:15
【问题描述】:

我对传递给协程任务的临时对象的生命周期感到困惑。考虑这个例子:

cppcoro::task<> UseObject(Object const& object);

cppcoro::task<> CallUseObject() {
    co_await UseObject(Object()); // is this valid?
}

如果这些是返回 void 的函数,那么传递给 UseObjectObject() 将在分号处被销毁(即在 UseObject 完成之后)。但是,我不确定这是否同样适用于协程。通过引用将临时值传递给例程安全吗?如果不在分号处,临时对象什么时候会被销毁?

此外,作为健全性检查,写作是否总是安全的:

cppcoro::task<> CallUseObject() {
    Object stayingalive;
    co_await UseObject(stayingalive);
}

因为staying_alive 在 co_await 完成后被销毁?

【问题讨论】:

  • 我很想说Object() 在声明的结尾处死了,但我可能是错的。似乎协程是“传值”的绝佳选择
  • 如果函数调用通过引用接收参数的协程,调用者函数负责传递对象的生命周期,直到协程完成。这实际上与同步调用的规则相同,但是现在您还应该处理函数退出但未完成并且所有临时对象都被破坏的情况。 co_await 运算符没有帮助,因为此运算符适用于返回值,只有在函数退出后才能获得。
  • 我最近使用 vs2019 的经验表明,您的第一个示例(Object()),直到 co_await 结束才调用析构函数。

标签: c++ c++20 c++-coroutine


【解决方案1】:

这实际上是带有current draftopen issue 的主题。引用问题:

目的是创建参数的副本/移动(如果需要),保留确切的类型(包括引用、r 引用等)。 11.4.4[dcl.fct.def.coroutine]/11 中的措辞似乎没有表达清楚。

基于此,协程框架似乎将捕获对临时的引用。

由于co_await 是一个表达式,临时值应该在它出现的完整表达式的末尾被销毁。上面的代码是否安全将取决于所涉及的两个协程的具体实现是否使 co_await 在调用 UseObject 时引用临时文件时安全。具体来说,请注意co_await 的作用取决于它所应用的表达式的类型以及它出现的协程的承诺类型。此外,UseObject(我们不知道它的定义)至少在原则上,可以根据给出的参考做各种奇怪的事情……

【讨论】:

  • 我认为这半部分回答了我的问题。你是说协程框架应该有一个参考。问题的另一半是参考何时失效。对象是否在 co_await 完成之前被销毁?或在分号处。如果我误解了,请纠正我。
  • 我会说它确实应该发生在分号处。 co_await 是一个表达式。 prvalue Object() 绑定到引用时实现的临时值将在完整表达式的末尾被销毁。
  • 好的。根据您的评论,此代码是安全的,因为协程存储了对在协程被销毁后被销毁的临时对象的引用。如果您合并您的答案和评论,那么我将接受答案。
  • @sudorm-rfslash 我认为一般来说这不能说是安全的。这是否安全取决于co_await 会做什么。 co_await 的作用取决于参数的类型以及它出现的协程的承诺类型。根据您问题中提供的信息,所有可以说的是协程调用将捕获对临时的引用。这是否安全取决于两个协程的具体实现......
  • 感谢更新。我希望委员会在标准化协程之前简化这些简单问题的答案。
猜你喜欢
  • 1970-01-01
  • 2015-12-11
  • 2012-04-24
  • 2012-03-03
  • 1970-01-01
  • 1970-01-01
  • 2015-01-10
  • 2019-07-27
  • 1970-01-01
相关资源
最近更新 更多