1

我对 C++11 中的新内存<memory>头的理解有点周,但据我所知,shared_ptr 是 refcounted ptr,这使得复制它真的非常昂贵(尤其是在例如 ARM arch 上)。并且 unique_ptr 几乎是围绕 new/delete 的非常轻量级的包装器。而且它是可移动的,因此它不受您创建它的范围的限制。
所以我的问题是:
在单线程代码使用中,shared_ptr 比 unique_ptr 更受欢迎吗?

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

4

2 回答 2

4

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

当您不太确定对象的生命周期是多少时使用shared_ptr<>,并且希望“房间里最后一个人关灯”——即,您不希望在没有客户端之前删除对象不再使用它。当您unique_ptr<>确切地知道谁将删除该对象时使用 - 即,当指向对象的生命周期由范围精确界定时。

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

于 2012-07-26T11:01:18.917 回答
2

这个问题问得好。

在多线程构建中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);
}
于 2012-07-26T12:19:57.083 回答