【问题标题】:Is it safe to capture `this` in a coroutine lambda (C++)在协程 lambda (C++) 中捕获“this”是否安全
【发布时间】:2021-08-03 01:15:14
【问题描述】:

我一直在使用 c++20 协程,我偶然发现了 this 问题,即 lambda 捕获的生命周期不会在协程的整个生命周期内延长。

我想知道捕获什么是安全的,因为我不得不将所有捕获复制到新对象中,如下所示:

[a1=object]() -> task<void> {
    // need to copy into a new object to safely reference for the lifetime of the coroutine
    auto object = a1;
    co_await something;
    // ...

当我在我的程序中明确捕获this 时:

[this]() -> {
    co_await something;
    this->....

我可以在暂停后引用this,没有问题。

但是,在阅读标准时,我发现:

An entity is captured by reference if it is implicitly or explicitly captured but not captured by copy. It is
unspecified whether additional unnamed non-static data members are declared in the closure type for entities
captured by reference.

鉴于它是否将指针创建为属性是“未指定的”,这是否意味着我很幸运?或者this 捕获有什么不同?

【问题讨论】:

  • 只要对象销毁后不使用lambda,对象销毁后的lambda不使用对象,都没有问题。其他任何事情要么是幸运的(程序立即崩溃),要么是不幸的(程序似乎可以工作)。
  • @Eljay 好吧,这与您所说的相反。使用 C++20 协程,协程的寿命比捕获的 lambda 变量长。所以这有点不同。检查我的第一个链接
  • 如果协程在指向对象的生命周期结束后取消引用this 指针(例如调用对象的非静态成员函数),则协程具有未定义的行为。
  • 但是在 lambda 生命周期结束之后呢?由于协程比 lambda 存在的时间更长。是否有可能尝试读取存储在 lambda 捕获中的 this 指针地址并导致段错误?

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


【解决方案1】:

程序员应该忽略标准中的那句话:它只允许实现分配比对具有引用捕获的 lambda 对象(尤其是内联调用运算符时)可能天真预期的更少的内存。 p>

【讨论】:

  • 一旦 lambda 执行,引用是否总是被复制到堆栈中?
  • @lufinkey: 如果必须存储它们(例如,通过std::function 使用),它们将像任何其他捕获一样位于闭包对象中(尽管有些对于局部变量和参数可能会合并到指向整个堆栈帧的指针中)。否则,它们就根本不存在:编译器只是已经知道捕获的实体在哪里。
  • 我不确定我是否真的理解。我只是想在我的协程期间不访问死内存。如果我编写了一个像这样捕获对象的协程,我需要在进入协程时执行复制到堆栈,如下所示:[a1=someObject]() -&gt; task&lt;void&gt; { auto someObject = a1; co_await something; /* attempt to access someObject */ } 否则访问someObject 指向死内存。我发现捕获this 时不需要发生这种情况。我不明白为什么。标准似乎很不清楚
  • 我不认为这是需要std::function 的情况,除非你正在做类似我所做的黑客修复here。但我只是想知道语义而不是修复。
  • @lufinkey: [this] 只是通过引用捕获*this,为其调用成员函数的对象)。如果那个 object 是活动的,无论特定的 call 是否返回,它和它的成员都是可用的。引用本身总是可用(即使它可能是悬空的),因为它是 lambda 的一部分——考虑堆栈,或者实现如何实际找到引用,只是分散注意力。 (在所有内容都内联的常见情况下,调用无法返回,但delete this; 仍可能使[this] 捕获无效。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-28
  • 1970-01-01
  • 2016-02-08
  • 2011-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多