单线程代码中是否有 std::shared_ptr 比 std::unique_ptr 更合适的用法

问题描述 投票:0回答:2

我对 C++11 中新内存

<memory>
标头的理解有点周,但据我所知,shared_ptr 是引用计数的 ptr,这使得复制它非常非常昂贵(特别是在 ARM arch 上)。 unique_ptr 几乎是 new/delete 的非常非常轻的包装器。而且它是可移动的,因此不会受到您创建它的范围的限制。
所以我的问题是:
是否存在单线程代码用法,其中shared_ptr优于unique_ptr?

我对这样的答案不感兴趣:让你的单线程代码为未来的多线程做好准备。假设代码是单线程的。

c++ c++11 std shared-ptr smart-pointers
2个回答
4
投票

您对线程的关注有点转移注意力;两者之间有明显的对比,并且与线程几乎没有关系。如果您在单线程环境中使用这些类,您也许可以关闭原子操作支持;例如,使用 Boost,定义宏

BOOST_SP_DISABLE_THREADS

当您不太确定某个对象的生命周期,并且希望“房间里最后一个关灯的人”时,您可以使用

shared_ptr<>
- 即,您不希望该对象成为删除直到没有客户端再使用它。当您确切知道谁将删除该对象时,即当所指向对象的生命周期由范围精确界定时,您可以使用
unique_ptr<>

确实,复制

shared_ptr<>
不是免费的,但它离“非常非常昂贵”还很远。您需要为引用计数开销付出一些代价,但这就是使用它的全部意义:您需要跟踪对象的客户端;虽然涉及一点成本,但您可以获得不泄漏对象的好处。


3
投票

在多线程构建中,基本上总是为

shared_ptr<>

所做的原子引用计数器增量/减量付费,即使对象从未在线程之间共享。


另一个缺点是

shared_ptr<>

的大小是普通指针大小的两倍。


由于这两个原因,

shared_ptr<>

对于性能关键型应用来说从来都不是一个好的选择。


多线程应用程序有几种类型的对象在线程之间共享,而大多数对象则不在线程之间共享。仅线程共享对象需要使用原子引用计数器递增/递减,而为大多数其他对象支付原子操作成本是愚蠢的。因此,为线程共享和线程非共享对象设置不同的(基本)类型并使用

boost::intrusive_ptr<>

来管理它们是很有意义的。线程共享对象有一个原子引用计数器,而线程非共享对象则有一个普通整数计数器。例如:


#include <atomic> #include <boost/intrusive_ptr.hpp> template<class Derived, class Counter> class RefCounter { Counter ref_count_; friend void intrusive_ptr_add_ref(RefCounter* p) { ++p->ref_count_; } friend void intrusive_ptr_release(RefCounter* p) { if(!--p->ref_count_) delete static_cast<Derived*>(p); } protected: RefCounter() : ref_count_() {} }; class NonThreadShared : public RefCounter<NonThreadShared, unsigned> {}; class ThreadShared : public RefCounter<ThreadShared, std::atomic<unsigned> > {}; int main() { boost::intrusive_ptr<NonThreadShared> p(new NonThreadShared); boost::intrusive_ptr<ThreadShared> q(new ThreadShared); }

© www.soinside.com 2019 - 2024. All rights reserved.