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

时间:2012-07-26 10:57:24

标签: c++ c++11 std smart-pointers

我对C ++ 11中新内存<memory>标题的理解是一个星期,但从我可以看出,shared_ptr是refcounted ptr,这使得复制它真的非常昂贵(特别是ARM)拱)。而unique_ptr几乎是关于new / delete的非常轻量级的包装器。并且它是可移动的,因此不会受到您创建它的范围的限制  所以我的问题是:
是否存在单线程代码用法,其中shared_ptr优先于unique_ptr?

我对以下答案不感兴趣:让你的单线程代码为未来的多线程做好准备。假定代码是并且将说singlthreaded。

2 个答案:

答案 0 :(得分:4)

你在这里穿线是一种红色的鲱鱼;两者之间有明显的对比,它与线程几乎没有任何关系。如果您在单线程环境中使用这些类,则可以关闭原子操作支持;例如,使用Boost,定义宏BOOST_SP_DISABLE_THREADS

当你不太确定对象的生命周期是什么时,你会使用shared_ptr<>,并希望“房间里的最后一个人关掉灯” - 也就是说,你不想要要删除的对象,直到没有客户端再使用它为止。当您确切知道要删除对象的人时,使用unique_ptr<> - 即,当指向对象的生命周期被范围精确划分时。

复制shared_ptr<>确实不是免费的,但是来自“非常非常昂贵”。您需要为引用计数开销支付一些费用,但这是使用它的全部要点:您需要跟踪对象的客户端;这需要一点费用,但你可以获得不泄漏物体的好处。

答案 1 :(得分:2)

这是一个非常好的问题。

在多线程构建中,基本上总是支付shared_ptr<>所做的原子引用计数器增量/减量,即使对象永远不会在线程之间共享。

另一个缺点是shared_ptr<>的大小是普通指针大小的两倍。

出于这两个原因shared_ptr<>从来就不是性能关键应用程序的好选择。

多线程应用程序有几种类型的对象在线程和大多数不共享的对象之间共享。使用原子引用计数器递增/递减仅对于线程共享对象是必需的,并且为大多数其他对象支付原子操作成本是愚蠢的。因此,为线程共享和线程非共享对象提供不同的(基本)类型并使用boost::intrusive_ptr<>管理它们是很有意义的。线程共享对象具有原子引用计数器,而线程非共享对象具有普通整数计数器。 E.g:

#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);
}