10

と を使用しCreatureて、アプリケーションの一部で作成および所有されるオブジェクトのコレクションがあります。std::make_sharedstd::shared_ptr

また、を使用して、オブジェクトCreature内の 0 または 1 の選択を追跡します。Worldstd::weak_ptr<Creature>

void World::SetSelection(const std::shared_ptr<Creature>& creature) {
    selection = creature;
}

std::shared_ptr<Creature> World::GetSelection() const {
    return selection.lock();
}

の呼び出し元はGetSelection、ポインターが空かどうかをチェックする責任があります。そうである場合、それは現在選択がないことを意味します。

これはすべて私の好みで完全に機能します。選択したものCreatureが自然な原因で (アプリケーションの他の場所で) 死ぬと、何も選択されなかったかのように再びGetSelectiona を返し始めます。nullptr

ただし、その場合、メンバーはまだの制御ブロックWorld::selectionを指しています。オブジェクトを作成するstd::shared_ptrために使用しているため、これは非常に大きくなる可能性があります (オブジェクトは適切なタイミングで適切に破棄されましたが、そのためのメモリはまだ割り当てられていることに気付きました)。これに変更することを検討しています:std::make_sharedCreatureCreatureGetSelection

std::shared_ptr<Creature> World::GetSelection() {
    const auto ret = selection.lock();
    if (!ret)
        selection.reset();

    return ret;
}

これにより、不要になったことに気付くとすぐにメモリが解放されます。厄介なことに、このバージョンのGetSelectionconst.

私の質問:

  1. GetSelectionこの状況でベスト プラクティスと見なされるのは、どのバージョンのですか?

  2. テンプレート化されたコードで同様のことが起こった場合、答えは変わりますsizeof(T)か? または、C++ 14 ではどこstd::make_shared<T[]>に関与する可能性がありますか?

  3. std::weak_ptr<T>::expired2 番目のバージョンが常に最適である場合、自分でそれを行わない理由は何lockですか?

4

2 に答える 2

4

最初に、 の配置戦略はオプションであることに注意してくださいstd::make_shared。つまり、標準では、実装がこの最適化を実行することを義務付けていません。これは拘束力のない要件です。つまり、完全に適合する実装では、それを無視することを選択できるということです。

質問に答えるには:

  1. 選択肢が 1 つしかないように思われる場合 (したがって、これらの制御ブロックを多数保持することでメモリの使用量が膨大になるわけではありません)、シンプルに保つことをお勧めします。メモリがボトルネック?これは私にとってマイクロ最適化を叫びます。を適用できる単純なコードを記述しconst、必要に応じて後で戻って最適化する必要があります。

  2. 答えは無条件に変わるわけではなく、問題のドメインとボトルネックが何であるかによって条件付きで変わります。「巨大な」(100 キロバイトなど) 1 つのオブジェクトを割り当てており、そのオブジェクトのスペースが、交換されるまで比較的使用されていない制御ブロック内で動き回っている場合、それはおそらくボトルネックではなく、おそらく価値がありません。 「解決」するために、より多くのコードを書く (本質的にエラーが発生しやすく、保守が難しく、解読が難しい)。

  3. std::weak_ptr::lockstd::weak_ptr::expiredはのように、 for C++11constの解釈の下では、constスレッド セーフである必要があります。したがって、 some が与えられた場合、 と の任意の組み合わせを同時にstd::weak_ptr呼び出しても安全でなければなりません。内部では、制御ブロックへのポインタが格納され、調べたり、インクリメントしたりします。アトミック カウンターを使用して、オブジェクトの有効期限が切れているかどうかを判断したり、ロックを取得できるかどうかを確認したりします。の内部に最適化を実装したい場合は、何らかの方法でコントロール ブロックの状態を検査し、ポインターの有効期限が切れている場合はコントロール ブロックへのポインターをアトミックに削除する必要があります。これは、lock()expired()std::weak_ptrstd::weak_ptrstd::weak_ptr、すべて小さな最適化のために。

于 2014-08-12T23:42:54.080 に答える