我对C++11最佳实践有一个问题。当清除一个共享指针时,我应该使用没有参数的reset()
函数,还是将shared_ptr
设置为nullptr
?例如:
std::shared_ptr<std::string> foo(new std::string("foo"));
foo.reset();
foo = nullptr;
这两种方法有真正的区别吗?还是每种方法都有优缺点?
我对C++11最佳实践有一个问题。当清除一个共享指针时,我应该使用没有参数的reset()
函数,还是将shared_ptr
设置为nullptr
?例如:
std::shared_ptr<std::string> foo(new std::string("foo"));
foo.reset();
foo = nullptr;
这两种方法有真正的区别吗?还是每种方法都有优缺点?
foo = nullptr
)是基于第一种形式定义的。根据C++11标准的第20.7.1.2.3/8-10段: unique_ptr& operator=(nullptr_t) noexcept;
因此,只需选择最能清晰表达意图的方法。就我个人而言,我更喜欢:
foo = nullptr;
由于这使得我们更清楚地表明指针应该是空的。然而,作为一般建议,请尽量减少需要显式地重置智能指针的情况。
此外,不要使用new
:
std::shared_ptr<std::string> foo(new std::string("foo"));
尽可能使用std::make_shared()
:
auto foo = std::make_shared<std::string>("foo");
unique_ptr
的,并且shared_ptr
没有operator=(nullptr_t)
方法。如果我使用foo = nullptr
,那么nullptr
会被转换为unique_ptr
,然后再转换为shared_ptr
,这样理解是否正确? - mdrshared_ptr
没有operator=(nullptr_t)
,因此将nullptr
分配给它需要进行转换。我们可能可以证明在优化构建中这无关紧要,但说“两个替代方案完全等价,即第二种形式(foo = nullptr)是基于第一种形式定义的”似乎完全是错误的。 - underscore_d我更倾向于使用 reset()
,因为它能明确表达意图。但是,尽可能编写您的代码,使您不需要显式清除 shared_ptr<>
,即确保在您本应清除它时,shared_ptr<>
退出其作用域。
如果您使用https://godbolt.org/进行检查,它们会有一些不同
通过使用gcc(7.2)
foo.reset();
生成的汇编代码
lea rax, [rbp-32]
mov rdi, rax
call std::__shared_ptr<int, (__gnu_cxx::_Lock_policy)2>::reset()
然而,foo = nullptr;
生成的结果是
lea rax, [rbp-16]
mov esi, 0
mov rdi, rax
call std::shared_ptr<int>::shared_ptr(decltype(nullptr))
lea rdx, [rbp-16]
lea rax, [rbp-32]
mov rsi, rdx
mov rdi, rax
call std::shared_ptr<int>::operator=(std::shared_ptr<int>&&)
lea rax, [rbp-16]
mov rdi, rax
call std::shared_ptr<int>::~shared_ptr()
它使用 nullptr 创建一个共享指针,将新创建的对象分配给变量,并调用析构函数来销毁字符串。
由于我不知道如何检查 reset() 函数中发生了什么。无法确定哪个更快。
通常情况下,智能指针可以自行处理。但如果您需要解决方案,reset()
在我看来是最好的选择。
foo = {}
也是一种选择! - Luc Dantonstd::shared_ptr<std::string> bar; foo = bar
?通常情况下,当我们将一个 shared_ptr 赋值给另一个 shared_ptr 时,它所指向的对象的引用计数会增加。那么在这种情况下会发生什么呢? - rivaldo4t