weak_ptr 的性能损失是什么?

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

我目前正在为游戏设计一个对象结构,在我的例子中最自然的组织变成了一棵树。作为智能指针的忠实粉丝,我专门使用

shared_ptr
。然而,在这种情况下,树中的子级将需要访问其父级(例如,地图上的生物需要能够访问地图数据,因此需要访问其父级的数据。

拥有的方向当然是地图拥有它的存在,因此保存指向它们的共享指针。然而,要从存在内部访问地图数据,我们需要一个指向父级的指针——智能指针方式是使用引用,因此

weak_ptr

然而,我曾经读到,锁定

weak_ptr
是一项昂贵的操作——也许这不再是事实了——但考虑到
weak_ptr
会经常被锁定,我担心这种设计注定性能不佳.

因此问题:

锁定weak_ptr 的性能损失是什么?有多重要?

c++ performance boost weak-ptr
3个回答
20
投票

来自 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() );
}

因此,詹姆斯·麦克内利斯的评论是正确的;这是复制构造

shared_ptr
的成本。


12
投票

对于我自己的项目,我能够通过添加

#define BOOST_DISABLE_THREADS 
在任何提升之前包括。 这避免了weak_ptr::lock的自旋锁/互斥开销,在我的项目中是 一个主要瓶颈。由于该项目不是多线程 wrt boost,我可以这样做。


11
投票

使用/取消引用 shared_ptr 几乎就像访问原始 ptr,锁定 weak_ptr 与常规指针访问相比是一个性能“重”操作,因为此代码必须是“线程感知”才能正常工作,以防万一另一个线程触发指针引用的对象的释放。至少,它必须执行某种互锁/原子操作,根据定义,该操作比常规内存访问慢得多。

像往常一样,查看正在发生的情况的一种方法是检查生成的代码

#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
需要先加载参考值,比原始版本需要额外加载一次。

callFuncShared:

调用FuncRaw:

callFuncWeak:

通过

weak_ptr
调用会产生 10 倍以上的代码,并且最多必须经过锁定的比较交换,这本身将比取消引用 raw 或 shared_ptr 花费 10 倍以上的 CPU 时间:

只有当共享计数器不为零时,它才能加载指向实际对象的指针并使用它(通过调用该对象,或创建一个

shared_ptr
)。

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