31

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

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

然而,我曾经读到锁定 aweak_ptr是一项昂贵的操作——也许这不再是真的了——但考虑到weak_ptr将经常被锁定,我担心这种设计注定会性能不佳。

因此问题是:

锁定weak_ptr 的性能损失是多少?它有多重要?

4

3 回答 3

17

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

因此,James McNellis 的评论是正确的;这是复制构建 a 的成本shared_ptr

于 2010-04-30T22:53:11.130 回答
10

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

于 2012-01-23T00:39:07.667 回答
6

使用/取消引用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作为引用传递,我们需要加载引用的值,这就是为什么不同之处只是 shared_ptr 版本的额外加载。

调用函数共享:

在此处输入图像描述

调用函数弱:

在此处输入图像描述

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

在此处输入图像描述

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

于 2020-05-07T09:42:13.493 回答