31

私は現在、ゲームのオブジェクト構造を設計していますが、私の場合、最も自然な構成はツリーになりました。スマートポインタの大ファンである私は、をshared_ptr独占的に使用しています。ただし、この場合、ツリー内の子はその親にアクセスする必要があります(たとえば、マップ上の存在はマップデータにアクセスできる必要があります-親のデータをエルゴします。

もちろん、所有する方向は、マップがその存在を所有することであるため、それらへの共有ポインターを保持します。ただし、存在内からマップデータにアクセスするには、親へのポインターが必要です。スマートポインターの方法は、参照を使用することweak_ptrです。

ただし、aのロックweak_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() );
}

エルゴ、ジェームズ・マクネリスのコメントは正しい。それはコピー構築のコストですshared_ptr

于 2010-04-30T22:53:11.130 に答える
10

私自身のプロジェクトでは、 #define BOOST_DISABLE_THREADS ブーストが含まれる前に追加することで、パフォーマンスを劇的に向上させることができました。これにより、私のプロジェクトでは大きなボトルネックであったweak_ptr::lockのスピンロック/ミューテックスのオーバーヘッドが回避されます。プロジェクトはブーストのマルチスレッドではないので、これを行うことができます。

于 2012-01-23T00:39:07.667 に答える
6

shared_ptrの使用/逆参照は、raw ptrへのアクセスとほとんど同じです。weak_ptrのロックは、通常のポインターアクセスと比較して、パフォーマンスの「重い」操作です。このコードは、別のスレッドがポインタによって参照されるオブジェクト。少なくとも、通常のメモリアクセスよりもはるかに遅い、ある種のインターロック/アトミック操作を実行する必要があります。

いつものように、何が起こっているかを確認する1つの方法は、生成されたコードを検査することです。

#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とrawポインタを介したアクセスは同じです。は参照として渡されたためshared_ptr、参照された値をロードする必要があります。そのため、shared_ptrバージョンの追加のロードは1つだけです。

callFuncShared:

ここに画像の説明を入力してください

callFuncWeak:

ここに画像の説明を入力してください

呼び出しweak_ptrは10倍多くのコードを生成し、せいぜいロックされた比較交換を実行する必要があります。これ自体は、rawまたはshared_ptrの逆参照よりも10倍以上のCPU時間を要します。

ここに画像の説明を入力してください

共有カウンターがゼロでない場合にのみ、実際のオブジェクトへのポインターをロードして使用できます(オブジェクトを呼び出すか、を作成することによりshared_ptr)。

于 2020-05-07T09:42:13.493 に答える