weak_ptr的性能损失是什么?

时间:2010-04-30 22:40:08

标签: c++ performance boost weak-ptr

我正在为游戏设计一个对象结构,在我的案例中,最自然的组织变成了一棵树。作为智能指针的忠实粉丝,我只使用shared_ptr。但是,在这种情况下,树中的孩子将需要访问它的父母(例如 - 地图上的生物需要能够访问他们的父母的数据。

拥有的方向当然是地图拥有它的存在,因此拥有它们的共享指针。为了从存在中访问地图数据,我们需要一个指向父节点的指针 - 智能指针的方式是使用引用,而不是weak_ptr

然而,我曾经读到锁定weak_ptr是一项昂贵的操作 - 可能这不再是真的 - 但考虑到weak_ptr会经常被锁定,我担心这个设计注定表现不佳。

因此问题:

锁定weak_ptr会有什么性能损失?它有多重要?

3 个答案:

答案 0 :(得分:13)

来自Boost 1.42源代码(<boost/shared_ptr/weak_ptr.hpp>第155行):

shared_ptr<T> lock() const // never throws
{
    return shared_ptr<element_type>( *this, boost::detail::sp_nothrow_tag() );
}

ergo,James McNellis的评论是正确的;这是复制构建shared_ptr的成本。

答案 1 :(得分:7)

对于我自己的项目,我能够通过添加来显着提高性能 在任何提升包括之前#define BOOST_DISABLE_THREADS 。 这避免了我的项目中的weak_ptr :: lock的spinlock / mutex开销 一个主要的瓶颈。由于该项目不是多线程的,所以我可以做到这一点。

答案 2 :(得分:2)

使用/取消引用shared_ptr几乎就像访问原始ptr一样,与常规指针访问相比,锁定weak_ptr是一项“繁重的”操作,因为此代码必须具有“线程意识”可以正常工作,以防其他线程触发释放该指针所引用的对象。至少,它必须执行某种互锁/原子操作,根据定义,它比常规的内存访问要慢得多。

和往常一样,查看发生情况的一种方法是inspect generated code

#include <memory>

class Test
{
public:
    void test();
};

void callFuncShared(std::shared_ptr<Test>& ptr)
{
    if (ptr)
        ptr->test();
}

void callFuncWeak(std::weak_ptr<Test>& ptr)
{
    if (auto p = ptr.lock())
        p->test();
}

void callFuncRaw(Test* ptr)
{
    if (ptr)
        ptr->test();
}

通过shared_ptr和原始指针进行访问是相同的。由于shared_ptr是作为参考传递的,因此我们需要加载参考值,这就是为什么差异仅是shared_ptr版本的一次额外加载。

callFuncShared:

enter image description here

callFuncWeak:

enter image description here

通过weak_ptr进行调用会产生10倍多的代码,充其量必须经过锁定的compare-exchange,与解引用raw或shared_ptr相比,它本身将花费10倍以上的CPU时间:

enter image description here

仅当共享计数器不为零时,它才能将指针加载到实际对象并使用它(通过调用对象或创建shared_ptr)。