Ann*_*nyo 6 c++ smart-pointers reference-counting shared-ptr
看这个例子:
#include <iostream>
#include <memory>
class Foo {
public:
Foo() { std::cout << "Foo()\n"; }
~Foo() { std::cout << "~Foo()\n"; }
};
int main(){
auto deleter = [](Foo* p) {
if(!p) { std::cout << "Calling deleter on nullptr\n"; }
delete p;
};
std::shared_ptr<Foo> foo;
std::cout << "\nWith non-null Foo:\n";
foo = std::shared_ptr<Foo>(new Foo, deleter);
std::cout << "foo is " << (foo ? "not ":"") << "null\n";
std::cout << "use count=" << foo.use_count() << '\n';
foo.reset();
std::cout << "\nWith nullptr and deleter:\n";
foo = std::shared_ptr<Foo>(nullptr, deleter);
std::cout << "foo is " << (foo ? "not ":"") << "null\n";
std::cout << "use count=" << foo.use_count() << '\n';
foo.reset();
std::cout << "\nWith nullptr, without deleter:\n";
foo = std::shared_ptr<Foo>(nullptr);
std::cout << "foo is " << (foo ? "not ":"") << "null\n";
std::cout << "use count=" << foo.use_count() << '\n';
foo.reset();
}
Run Code Online (Sandbox Code Playgroud)
输出是:
With non-null Foo:
Foo()
foo is not null
use count=1
~Foo()
With nullptr and deleter:
foo is null
use count=1
Calling deleter on nullptr
With nullptr, without deleter:
foo is null
use count=0
Run Code Online (Sandbox Code Playgroud)
在这里我们看到shared_ptr在使用自定义删除器初始化时调用nullptr包含的删除器。看起来,当使用自定义删除器初始化时,shared_ptr认为它“拥有” nullptr,因此在删除任何其他拥有的指针时尝试删除它。尽管在未指定删除器时不会发生这种情况。
这是有意的行为吗?如果是这样,这种行为背后的原因是什么?
tl;dr:是的,这是有意的。
\n\n这非常微妙。
\n\nShared_ptr 可以处于两种状态:
\n\nget()可能会返回nullptr(尽管存在一些改变此后置条件的因素)p;get()回报p。shared_ptr使用空指针构造 a实际上会导致它不为空!get()回归的p意思是get()归来nullptr,但这并不会使它为空。
由于默认删除器只是执行delete p, 和delete nullptr是无操作,因此这通常并不重要。但是,正如您所看到的,如果您提供自己的删除程序,您可以观察到这种差异。
我不知道这是为什么。一方面,我可以看到一种防止在 nullptr 情况下调用删除器的情况,因为人们通常认为 ashared_ptr(nullptr)是“空”(尽管技术上它不是);另一方面,如果愿意的话,我可以看到让删除者做出这个决定的情况(伴随着分支的开销)。
您在这里包含对 null 的检查是正确的。
\n\n一些法律术语来自[util.smartptr.shared.const]:
\n\n\n\n\n
template<class Y, class D> shared_ptr(Y* p, D d);
\n \n \ntemplate<class Y, class D, class A> shared_ptr(Y* p, D d, A a);template<class D> shared_ptr(nullptr_t p, D d);template<class D, class A> shared_ptr(nullptr_t p, D d, A a);9) 要求: 构造和初始化
\n\nd类型的删除器不得抛出异常。表达方式Dstd::move(d)d(p)应具有明确定义的行为并且不应引发异常。A 应满足 Cpp17Allocator 要求(表 34)。10)作用:构造一个
\n\nshared_\xc2\xadptr拥有该对象p和删除器的对象d。当T不是数组类型时,第一个和第二个构造函数启用shared_\xc2\xadfrom_\xc2\xadthiswithp。第二个和第四个构造函数应使用 的副本a来分配内存供内部使用。如果抛出异常,d(p)则调用。11) 确保:
\nuse_\xc2\xadcount() == 1 && get() == p.
(请注意,以下情况没有豁免!p。)
并来自[util.smartptr.shared.dest]:
\n\n\n\n\n
~shared_ptr();1)效果:
\n\n\n
\n- 如果
\n*this为空或与另一个shared_\xc2\xadptr实例共享所有权 (use_\xc2\xadcount() > 1),则没有副作用。- 否则,如果
\n*this拥有一个对象p和一个删除器d,d(p)则被调用。- 否则,
\n*this拥有一个指针p,并被delete p调用。
旁注:我认为上述段落中短语“拥有一个对象”和“拥有一个指针”之间的混淆是一个编辑问题。
\n\n我们还可以在cppreference.com 的~shared_ptr文章中看到这一点:
\n\n\n与 不同,即使托管指针为空,也会调用 的
\nstd::unique_ptr删除器。std::shared_ptr
(请使用文档!)
\n| 归档时间: |
|
| 查看次数: |
1146 次 |
| 最近记录: |