执行 lambda 主体时捕获 shared_ptr 释放

Captured shared_ptr released while executing the lambda body

我在 C++ 中有一个嵌套的 lambda,也就是说,一个内部 lambda 包含在一个中间 lambda 中,它也包含在一个外部 lambda 中。

我在外层 lambda 中创建了一个 shared_ptr,我将其按值传递给中间 lambda,在其中我创建了内层 lambda,声明后捕获的 shared_ptr 似乎是释放,可以通过 use_count() 变为零来确认。为什么?

完整代码:

#include <cstdio>
#include <functional>
#include <memory>

struct container;
using func_type = std::function<void(container&)>;
struct container {
  explicit container(int id, func_type next) : id{id}, next{next} {
    printf("contianer (%d)\n", id);
  }
  func_type next;
  int id;
  ~container() {
    printf("~contianer (%d)\n", id);
  }
};

struct value_type {
  ~value_type() {
    printf("~value_type\n");
  }
};

int main() {
  container c{0, [](container& c1) {
    std::shared_ptr<value_type> value = std::make_shared<value_type>();
    c1 = container{1, [value](container& c2) mutable {
      printf("value.use_count(): %d\n", value.use_count());
      c2 = container{2, [](container& c3) mutable {
        printf("finished\n");
        return;
      }};
      printf("value.use_count(): %d\n", value.use_count());
      return;
    }};
    return;
  }};
  c.next(c);
  c.next(c);
  return 0;
}

输出:(神栓:https://godbolt.org/z/9PbboEPfK

Program returned: 0
Program stdout
contianer (0)
contianer (1)
~contianer (1)
value.use_count(): 1
contianer (2)
~value_type
~contianer (2)
value.use_count(): 0
~contianer (2)

当您第一次调用 c.next(c) 时,您是 运行 函数 c.next,这将导致 c.next 被新的 lambda 替换,即拥有一个共享指针。在第一个 c.next(...) 调用此 shared_ptr 之后,拥有 lambda 的将是新的 c.next.

当您再次调用 c.next(c) 时,您将 that lambda 替换为没有 shared_ptr 所有权的 lambda,因此 shared_ptr当替换赋值发生时,它应该被破坏,因为除了超出范围的闭包之外没有其他东西引用它。

如果这是真实的代码——我的意思是如果它是真实的代码,请不要以这种方式做任何你正在做的事情——你可以通过拥有内部 lambda 来获得你似乎想要的行为,那个只是打印“完成”,同时捕获 value.