6

ゲームのいくつかの場所で、デザインでポインタ ツー ポインタを使用したいと思っています。たとえば、OpenGLRenderer頂点/インデックス/texcoord データを指定してメッシュを作成するクラス、マテリアル プロパティを指定してマテリアルを作成するクラスがあります。次に、ResourceManifestファイルからメッシュ/マテリアルをキャッシュし、これらのリソースの 1 つをロードすると、OpenGLRenderer. そこでカップリングがあります。

私は通常、次の関係に誘惑されるコーディング時に RAII 設計を採用するのが好きです。

ResourceManifest(OpenGLRenderer** renderer);

OpenGL コンテキストが取り壊され、ウィンドウを再作成するときなど、すべての OpenGL 状態固有のものを再初期化する必要がある場合、私は を再作成しOpenGLRenderer、コンストラクター/デストラクタにすべての作業を行わせ、ResourceManifestそれを使用することは決して賢明ではありません。 .

私が疑問に思っているのは、これが単純な古いポインターツーポインターを使用するのに十分な正当化であるかどうかです。利用可能な最新のツールまたは手法はありますか? たとえば、さまざまな smart_ptrs を見てきましたが、新しい smart_ptrs を渡さずに管理対象オブジェクトを再作成したいので、目前の問題に対処していません。

4

3 に答える 3

3

他の人がすでに述べたように、スマート ポインターを参照できます。

ただし、スマート ポインタ機能以外の機能も提供したい場合、特に基になるデータ構造が同種でない場合は、コードをイテレータにすることができます。繰り返しますが、これはポインターからポインターへの使用方法の問題です。その後、最終的に使用するインターフェイスが何であれ、それ自体がスマート ポインターにラップされる可能性があります。

于 2013-07-31T21:59:17.930 に答える
1

私が疑問に思っているのは、これが単純な古いポインターツーポインターを使用するのに十分な正当化であるかどうかです。利用可能な最新のツールまたは手法はありますか? 私

特定のシナリオでは、次のようなものを使用できます。

  1. OpenGLリソースがOpenGLリソースによって使用される汎用クラスである場所ResourceLoaderを含むというクラスがあります。std::map<ResourceId, std::weak_ptr<OpenGLResource> >ResourceID は、特定のリソースを識別するために使用するものです (ファイル名など)
  2. 新しいリソースResourceLoaderチェック マップを読み込むと、 はそれらweak_ptrを に変換してshared_ptr返します。map に sがない場合weak_ptr、またはそれらが NULL の場合、彼は new を作成しshared_ptr、それを map にプッシュしweak_ptrて返します。

    Semi-C++ 疑似コード (未チェック、タイプミスや構文エラーが含まれている可能性が高い):

      typedef std::shared_ptr<Resource> ResourcePtr;
      typedef std::weak_ptr<Resource> ResourceWeakPtr;
      typedef std::map<ResourceId, ResourceWeakPtr> ResourceMap;
    
      class Loader{
      public:
           ....            
          ResourcePtr loadResource(ResourceId id){
                 ResourceMap::iterator found = resoruceMap.find(id);
                 ResourcePtr result;
                 if ((found == resourceMap.end()) || !(result = found->second.lock())){
                      result = createResource(id);
                      resourceMap.insert(std::make_pair(id, ResourceWeakPtr(result)));
                 }
                 return result;                     
          }
          void reloadAllResources(){
                 for (ResourceMap::iterator i = resourceMap.begin(); i != resourceMap.end(); i++){
                      ResourcePtr cur = i->second.lock();
                      if (cur)
                           cur->reload();
                 }
          }
      protected:
          ResourceMap resourceMap;
          ResourcePtr createResource(ResourceId id){
                return ResourcePtr(new Resource());
          }
      };  
    
  3. 失われたリソースを再ロードする場合は、resourceMap を反復処理し、有効期限が切れていないすべてのオブジェクトで reload を呼び出すだけです。見るreloadAllResources
于 2013-07-31T22:33:11.827 に答える
0

あなたの質問を完全に理解しているかどうかさえわかりませんが、試してみてくださいstd::weak_ptr

次の (不自然な) 例を考えてみましょう。

#include<memory>
#include<iostream>

class Renderer {
 public:
  Renderer()
      : m_calls(0) { }
  void render() {
    m_calls++;
    std::cout<<"Issued render call #"<<m_calls<<std::endl;
  }
  void reset() {
    std::cout<<"Reset called"<<std::endl;
    m_calls = 0;
  }
 private:
  size_t m_calls;  
};

class Context {
 public:
  Context(std::shared_ptr<Renderer> prenderer)
      : m_prenderer(prenderer) {
  }
  void build_cache() {
    if(auto renderer = m_prenderer.lock()) {
      renderer->render();
    } else {
      std::cout<<"Handle the case when I don't have a renderer to work with"<<std::endl;
    }
  }  
 private:
  std::weak_ptr<Renderer> m_prenderer;  
};


int main() {
  auto renderer = std::make_shared<Renderer>();
  Context ctx(renderer);
  ctx.build_cache();
  ctx.build_cache();
  std::cout<<"Here I reset the renderer"<<std::endl;
  renderer->reset();
  ctx.build_cache();

}

次のようにコンパイル: g++ example.cpp -std=c++11(gcc 4.7.2)。出力:

Issued render call #1
Issued render call #2
Here I reset the renderer
Reset called
Issued render call #1

の目的はstd::weak_ptr、所有権を共有せずにポインターを共有することです。したがって、 をリセットまたは完全に再作成することができますがRenderer、それは にとって重要ではありませんContext。また、null ポインターへの逆参照には、明確に定義された動作があります。

于 2013-07-31T22:37:05.683 に答える