按值捕获 shared_ptr 的 lambda 如何影响它的 use_count()?
How does a lambda that captures a shared_ptr by value affect its use_count()?
我很好奇 shared_ptr 在 lambda 中被值捕获时的生命周期。
我原以为只要 lambda 仍在内存中,它的 use_count()
就始终 >= 1,但我的测试显示出一些意想不到的东西:使用计数下降到 0,然后在 lambda 内部递增到 1 body...
这是我测试的:
- 创建 shared_ptr
- 定义一个 lambda 来捕获 shared_ptr 值
- 重置shared_ptr
- 运行 λ
在第 3 阶段,shared_ptr 的 use_count()
降为 0 - 但 object 没有被破坏。在阶段 4 - 在 lambda 内部 - use_count()
回到 1。在 lambda 为 运行 之后,use_count()
回到 0,但是 object 直到lambda 被销毁。
我想知道这是怎么回事/为什么会这样?
不应该 use_count()
在 lambda 定义之后是 2 然后在 lambda 内部是 1 吗?
#include <iostream>
#include <memory>
class Foo {
public:
Foo( int v = 0 ) : val(v) {}
~Foo(){
std::cout << "--- Foo destroyed ---" << std::endl;
}
int val = 0;
};
void logPtr( const std::shared_ptr<Foo>& p ){
std::cout << "ptr: refs = " << p.use_count();
if (p) {
std::cout << ", val = " << p->val << std::endl;
}
else {
std::cout << ", nullptr" << std::endl;
}
}
int main() {
std::shared_ptr<Foo> ptr = std::make_shared<Foo>( 0 );
logPtr(ptr);
std::cout << "--- define lambda ---\n";
auto lambda = [=]() {
std::cout << "--- run lambda ---\n";
if (ptr) { ptr->val++; }
logPtr(ptr);
std::cout << "--- end lambda ---\n";
};
logPtr(ptr);
std::cout << "--- reset ptr ---\n";
ptr.reset();
logPtr(ptr);
// run lambda
lambda();
logPtr(ptr);
}
这是输出:
ptr: refs = 1, val = 0
--- define lambda ---
ptr: refs = 2, val = 0
--- reset ptr ---
ptr: refs = 0, nullptr
--- run lambda ---
ptr: refs = 1, val = 1
--- end lambda ---
ptr: refs = 0, nullptr
--- Foo destroyed ---
Shouldn't use_count()
be 2 after the lambda definition
是:
--- define lambda ---
ptr: refs = 2, val = 0
and then 1 inside the lambda?
是:
--- run lambda ---
ptr: refs = 1, val = 1
您感到困惑的部分与 lambda 无关。您可以通过创建共享指针的简单副本来产生相同的效果:
std::shared_ptr<Foo> ptr = std::make_shared<Foo>( 0 );
logPtr( ptr );
std::cout << "--- define lambda ---\n";
auto cpy = ptr;
logPtr(ptr);
std::cout << "--- reset ptr ---\n";
ptr.reset();
logPtr(ptr);
// run "lambda"
{
std::cout << "--- run lambda ---\n";
if (cpy) {
cpy->val++;
}
logPtr( cpy );
std::cout << "--- end lambda ---\n";
}
logPtr( ptr );
您似乎缺少的是 reset()
的语义。作为cppreference explains,它
Releases the ownership of the managed object, if any.
这意味着
If *this
already owns an object and it is the last shared_ptr
owning it, the object is destroyed through the owned deleter.
在您的代码中,最初有两个共享指针,共享引用对象的所有权。
ptr.reset()
之后,第一个指针不再是所有者。它重置回 null
/ 0
。但是,第二个指针(lambda 内部的副本)仍然是所有者并使引用的对象保持活动状态(现在 use_count
为 1)。
您的代码的其余部分只是检查两个不同的指针:一个仍然拥有该对象,另一个不拥有任何东西。
使用原始指针的等效代码如下所示:
Foo *ptr = new Foo(0);
Foo *cpy = ptr; // create a copy
ptr = null; // "reset" the first pointer
logPtr(cpy); // examine the copy
delete cpy; // release the object through the last active pointer
我很好奇 shared_ptr 在 lambda 中被值捕获时的生命周期。
我原以为只要 lambda 仍在内存中,它的 use_count()
就始终 >= 1,但我的测试显示出一些意想不到的东西:使用计数下降到 0,然后在 lambda 内部递增到 1 body...
这是我测试的:
- 创建 shared_ptr
- 定义一个 lambda 来捕获 shared_ptr 值
- 重置shared_ptr
- 运行 λ
在第 3 阶段,shared_ptr 的 use_count()
降为 0 - 但 object 没有被破坏。在阶段 4 - 在 lambda 内部 - use_count()
回到 1。在 lambda 为 运行 之后,use_count()
回到 0,但是 object 直到lambda 被销毁。
我想知道这是怎么回事/为什么会这样?
不应该 use_count()
在 lambda 定义之后是 2 然后在 lambda 内部是 1 吗?
#include <iostream>
#include <memory>
class Foo {
public:
Foo( int v = 0 ) : val(v) {}
~Foo(){
std::cout << "--- Foo destroyed ---" << std::endl;
}
int val = 0;
};
void logPtr( const std::shared_ptr<Foo>& p ){
std::cout << "ptr: refs = " << p.use_count();
if (p) {
std::cout << ", val = " << p->val << std::endl;
}
else {
std::cout << ", nullptr" << std::endl;
}
}
int main() {
std::shared_ptr<Foo> ptr = std::make_shared<Foo>( 0 );
logPtr(ptr);
std::cout << "--- define lambda ---\n";
auto lambda = [=]() {
std::cout << "--- run lambda ---\n";
if (ptr) { ptr->val++; }
logPtr(ptr);
std::cout << "--- end lambda ---\n";
};
logPtr(ptr);
std::cout << "--- reset ptr ---\n";
ptr.reset();
logPtr(ptr);
// run lambda
lambda();
logPtr(ptr);
}
这是输出:
ptr: refs = 1, val = 0
--- define lambda ---
ptr: refs = 2, val = 0
--- reset ptr ---
ptr: refs = 0, nullptr
--- run lambda ---
ptr: refs = 1, val = 1
--- end lambda ---
ptr: refs = 0, nullptr
--- Foo destroyed ---
Shouldn't
use_count()
be 2 after the lambda definition
是:
--- define lambda --- ptr: refs = 2, val = 0
and then 1 inside the lambda?
是:
--- run lambda --- ptr: refs = 1, val = 1
您感到困惑的部分与 lambda 无关。您可以通过创建共享指针的简单副本来产生相同的效果:
std::shared_ptr<Foo> ptr = std::make_shared<Foo>( 0 );
logPtr( ptr );
std::cout << "--- define lambda ---\n";
auto cpy = ptr;
logPtr(ptr);
std::cout << "--- reset ptr ---\n";
ptr.reset();
logPtr(ptr);
// run "lambda"
{
std::cout << "--- run lambda ---\n";
if (cpy) {
cpy->val++;
}
logPtr( cpy );
std::cout << "--- end lambda ---\n";
}
logPtr( ptr );
您似乎缺少的是 reset()
的语义。作为cppreference explains,它
Releases the ownership of the managed object, if any.
这意味着
If
*this
already owns an object and it is the lastshared_ptr
owning it, the object is destroyed through the owned deleter.
在您的代码中,最初有两个共享指针,共享引用对象的所有权。
ptr.reset()
之后,第一个指针不再是所有者。它重置回 null
/ 0
。但是,第二个指针(lambda 内部的副本)仍然是所有者并使引用的对象保持活动状态(现在 use_count
为 1)。
您的代码的其余部分只是检查两个不同的指针:一个仍然拥有该对象,另一个不拥有任何东西。
使用原始指针的等效代码如下所示:
Foo *ptr = new Foo(0);
Foo *cpy = ptr; // create a copy
ptr = null; // "reset" the first pointer
logPtr(cpy); // examine the copy
delete cpy; // release the object through the last active pointer