执行 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
.
我在 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
.