为什么实例化一个 shared_ptr 调用析构函数?
Why instantiating a shared_ptr calling destructor?
谁能解释一下为什么class bar
的析构函数在同类型对象初始化的那一行被调用?
#include <memory>
#include <iostream>
using namespace std;
class bar
{
public:
bar() {}
~bar() { std::cout << "destructor called " << std::endl; }
};
class foo
{
public:
foo(std::shared_ptr<bar> barP) {}
};
int main() {
std::shared_ptr<foo> f;
std::cout << "before init " << std::endl;
f = std::shared_ptr<foo>(new foo(std::shared_ptr<bar>(new bar())));
std::cout << "after init" << std::endl;
}
输出:
before init
destructor called
after init
首先,你不应该这样实例化shared_ptr
,使用make_shared
来实例化shared_ptr
。请检查修改后的代码 -
#include <memory>
#include <iostream>
using namespace std;
class bar
{
public:
bar() {}
~bar() { std::cout << "destructor called " << std::endl; }
};
class foo
{
public:
foo(std::shared_ptr<bar> barP) {}
};
int main() {
std::shared_ptr<foo> f;
std::cout << "before init " << std::endl;
std::shared_ptr<bar> b = std::make_shared<bar>();
f = std::make_shared<foo>(b);
std::cout << "after init" << std::endl;
}
以上程序的输出-
before init
after init
destructor called
通常,您的代码正在将 new bar
传递给 foo
的构造函数。并且没有人持有 bar
共享指针的所有权。因此,引用计数变为 0 并被删除,因此正在调用析构函数。
进一步阅读:make_shared vs new
这是因为 bar
实例仅在 foo
构造函数的持续时间内存在。所以它被构造,传递到 shared_ptr
,然后传递到 foo
构造函数。一旦该构造函数完成(即使在同一行),表达式本身也完成,因此 shared_ptr
完成,并析构。
在 main
的末尾 cout
之前,您仍然有一个 shared_ptr
到 f
中的 foo,但是未命名的 shared_ptr
您的 bar
对象已经消失 "out of scope".
这条语句:
f = std::shared_ptr<foo>(new foo(std::shared_ptr<bar>(new bar())));
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
构造一个临时的 shared_ptr
,它在语句末尾超出范围。在那一点上,shared_ptr
消失了,带走了 bar
(因为没有 shared_ptr
的副本仍然存在)。
但是如果你把foo
改成这样:
class foo
{
public:
foo(std::shared_ptr<bar> barP) { m_bar = barP; }
std::shared_ptr<bar> m_bar;
};
那么您得到的输出可能就是您所期望的,因为 foo
维护着 shared_ptr
的副本,直到它 (foo
) 超出范围并且该副本保留bar
活着:
before init
after init
destructor called
谁能解释一下为什么class bar
的析构函数在同类型对象初始化的那一行被调用?
#include <memory>
#include <iostream>
using namespace std;
class bar
{
public:
bar() {}
~bar() { std::cout << "destructor called " << std::endl; }
};
class foo
{
public:
foo(std::shared_ptr<bar> barP) {}
};
int main() {
std::shared_ptr<foo> f;
std::cout << "before init " << std::endl;
f = std::shared_ptr<foo>(new foo(std::shared_ptr<bar>(new bar())));
std::cout << "after init" << std::endl;
}
输出:
before init
destructor called
after init
首先,你不应该这样实例化shared_ptr
,使用make_shared
来实例化shared_ptr
。请检查修改后的代码 -
#include <memory>
#include <iostream>
using namespace std;
class bar
{
public:
bar() {}
~bar() { std::cout << "destructor called " << std::endl; }
};
class foo
{
public:
foo(std::shared_ptr<bar> barP) {}
};
int main() {
std::shared_ptr<foo> f;
std::cout << "before init " << std::endl;
std::shared_ptr<bar> b = std::make_shared<bar>();
f = std::make_shared<foo>(b);
std::cout << "after init" << std::endl;
}
以上程序的输出-
before init
after init
destructor called
通常,您的代码正在将 new bar
传递给 foo
的构造函数。并且没有人持有 bar
共享指针的所有权。因此,引用计数变为 0 并被删除,因此正在调用析构函数。
进一步阅读:make_shared vs new
这是因为 bar
实例仅在 foo
构造函数的持续时间内存在。所以它被构造,传递到 shared_ptr
,然后传递到 foo
构造函数。一旦该构造函数完成(即使在同一行),表达式本身也完成,因此 shared_ptr
完成,并析构。
在 main
的末尾 cout
之前,您仍然有一个 shared_ptr
到 f
中的 foo,但是未命名的 shared_ptr
您的 bar
对象已经消失 "out of scope".
这条语句:
f = std::shared_ptr<foo>(new foo(std::shared_ptr<bar>(new bar())));
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
构造一个临时的 shared_ptr
,它在语句末尾超出范围。在那一点上,shared_ptr
消失了,带走了 bar
(因为没有 shared_ptr
的副本仍然存在)。
但是如果你把foo
改成这样:
class foo
{
public:
foo(std::shared_ptr<bar> barP) { m_bar = barP; }
std::shared_ptr<bar> m_bar;
};
那么您得到的输出可能就是您所期望的,因为 foo
维护着 shared_ptr
的副本,直到它 (foo
) 超出范围并且该副本保留bar
活着:
before init
after init
destructor called