6

我发现自己在游戏中的一些地方想在我的设计中使用指针对指针。例如,我有一个类OpenGLRenderer,它创建给定顶点/索引/texcoord数据的网格,给定材质道具等的材质,然后一个ResourceManifest从文件缓存网格/材质的类,并在加载其中一个资源时使用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. 有一个类ResourceLoader,其中包含std::map<ResourceId, std::weak_ptr<OpenGLResource> >OpenGL 资源是 OpenGL 资源使用的通用类。ResourceID 是您用来识别特定资源的任何内容(文件名等)
  2. 当您加载新资源时,会ResourceLoader检查 map for weak_ptr's 将它们转换为shared_ptr并返回它们。如果 map 中没有weak_ptrs,或者它们为 NULL,则他创建 new shared_ptr,将其推weak_ptr送到 map 中,然后返回它。

    半 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是共享指针而不共享所有权。因此,您可以重置或完全重新创建您RendererContext. 此外,对空指针的取消引用具有明确定义的行为。

于 2013-07-31T22:37:05.683 回答