我有一个关于 C++11 最佳实践的问题。清除 shared_ptr 时,我应该使用reset()
不带参数的函数,还是应该将其设置shared_ptr
为nullptr
?例如:
std::shared_ptr<std::string> foo(new std::string("foo"));
foo.reset();
foo = nullptr;
有什么真正的区别,或者这两种方法都有优点/缺点吗?
我有一个关于 C++11 最佳实践的问题。清除 shared_ptr 时,我应该使用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;
8效果:
reset()
。9后置条件:
get() == nullptr
10返回:
*this
。
因此,只需选择其意图对您来说最清晰的那个。就个人而言,我更喜欢:
foo = nullptr;
因为它使我们希望指针为空变得更加明显。但是,作为一般建议,请尽量减少需要显式重置智能指针的情况。
此外,而不是使用new
:
std::shared_ptr<std::string> foo(new std::string("foo"));
尽可能考虑使用std::make_shared()
:
auto foo = std::make_shared<std::string>("foo");
我更喜欢reset()
它,因为它表明了意图。但是,尝试编写您的代码,以便您不需要显式清除 a shared_ptr<>
,即确保 ashared_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()
在我看来,这是你最好的选择。