私は数年前からポインターを扱ってきましたが、C++11 のスマート ポインター (つまり、一意、共有、および弱い) に移行することを決定したのはつい最近のことです。私はそれらについてかなりの調査を行い、これらが私が導き出した結論です:
- ユニークなポインタは素晴らしいです。それらは独自のメモリを管理し、生のポインターと同じくらい軽量です。可能な限り、生のポインターよりも unique_ptr を優先します。
- 共有ポインタは複雑です。参照カウントのため、かなりのオーバーヘッドがあります。それらをconst参照で渡すか、あなたのやり方の誤りを後悔してください。それらは悪ではありませんが、慎重に使用する必要があります。
- 共有ポインターはオブジェクトを所有する必要があります。所有権が必要ない場合は、ウィーク ポインターを使用します。weak_ptr をロックすると、shared_ptr コピー コンストラクターと同等のオーバーヘッドが発生します。
- とにかく廃止された auto_ptr の存在を無視し続けます。
したがって、これらの信条を念頭に置いて、コードベースを修正して新しい光沢のあるスマートポインターを利用することに着手し、できるだけ多くの生のポインターをボードにクリアすることを完全に意図しています。しかし、C++11 のスマート ポインターを最大限に活用する方法について、私は混乱してきました。
たとえば、単純なゲームを設計しているとしましょう。架空の Texture データ型を TextureManager クラスにロードすることが最適であると判断しました。これらのテクスチャは複雑であるため、値で渡すことはできません。さらに、ゲーム オブジェクトには、オブジェクトの種類 (車、ボートなど) に応じて特定のテクスチャが必要であると仮定します。
以前は、テクスチャをベクター (または unordered_map などの他のコンテナー) にロードし、これらのテクスチャへのポインターをそれぞれのゲーム オブジェクト内に格納して、レンダリングが必要なときにそれらを参照できるようにしていました。テクスチャがポインターよりも長く存続することが保証されていると仮定しましょう。
私の質問は、このような状況でスマート ポインターを最大限に活用する方法です。いくつかのオプションが表示されます:
テクスチャをコンテナに直接格納してから、各ゲーム オブジェクトで unique_ptr を構築します。
class TextureManager { public: const Texture& texture(const std::string& key) const { return textures_.at(key); } private: std::unordered_map<std::string, Texture> textures_; }; class GameObject { public: void set_texture(const Texture& texture) { texture_ = std::unique_ptr<Texture>(new Texture(texture)); } private: std::unique_ptr<Texture> texture_; };
ただし、これについての私の理解では、渡された参照から新しいテクスチャがコピー構築され、それが unique_ptr によって所有されるということです。これは、テクスチャを使用するゲーム オブジェクトと同じ数のテクスチャのコピーを持つことになるので、非常に望ましくないと思います。
テクスチャを直接保存するのではなく、共有ポインタをコンテナに保存します。共有ポインタを初期化するには、make_shared を使用します。ゲーム オブジェクトでウィーク ポインターを構築します。
class TextureManager { public: const std::shared_ptr<Texture>& texture(const std::string& key) const { return textures_.at(key); } private: std::unordered_map<std::string, std::shared_ptr<Texture>> textures_; }; class GameObject { public: void set_texture(const std::shared_ptr<Texture>& texture) { texture_ = texture; } private: std::weak_ptr<Texture> texture_; };
unique_ptr の場合とは異なり、テクスチャ自体をコピーして構築する必要はありませんが、ゲーム オブジェクトのレンダリングは、weak_ptr を毎回ロックする必要があるためコストがかかります (新しい shared_ptr をコピーして構築するのと同じくらい複雑です)。
要約すると、私の理解は次のとおりです。一意のポインターを使用する場合、テクスチャをコピーして構築する必要があります。あるいは、共有ポインターとウィーク ポインターを使用する場合、ゲーム オブジェクトを描画するたびに共有ポインターを基本的にコピー構築する必要があります。
スマート ポインターは生のポインターよりも本質的に複雑になることを理解しているため、どこかで損失を被る必要がありますが、これらのコストはどちらもおそらく本来あるべきよりも高いようです。
誰かが私を正しい方向に向けることができますか?
長々と読んでしまい申し訳ありません。お時間をいただきありがとうございます。