C ++中指针指针的替代方案?

时间:2013-07-31 21:47:38

标签: c++ pointers smart-pointers

我发现自己在游戏中的几个地方想要在我的设计中使用指针指针。例如,我有一个类OpenGLRenderer,它创建给定顶点/ indice / texcoord数据的网格,给定材质道具的材料等,然后是一个类ResourceManifest,它从文件中缓存网格/材料,并在加载一个这些资源使用OpenGLRenderer创建它的实例。所以那里有一个耦合。

我通常喜欢在编码时使用RAII设计,这会让我想到以下关系:

ResourceManifest(OpenGLRenderer** renderer);

因为当OpenGL上下文被拆除并且所有OpenGL状态特定的东西需要重新初始化时,例如重新创建窗口时,我只是重新创建OpenGLRenderer并让构造函数/析构函数完成所有工作ResourceManifest使用它永远不会更聪明。

我想知道的是,如果这足以证明使用普通的旧指针指针,是否还有更现代的工具或技术?我一直在寻找各种smart_ptrs,但他们并没有处理手头的问题,因为我想重新创建托管对象而不会传递新的smart_ptrs。

3 个答案:

答案 0 :(得分:3)

正如其他人已经说过的那样,你可以引用智能指针。

但是,如果您还希望提供智能指针之外的功能,则可以将代码转换为迭代器,尤其是在底层数据结构不同的情况下。同样,这是你如何使用指针指针的问题。然后,你最终使用的任何接口本身都可以用智能指针包装。

答案 1 :(得分:1)

  

我想知道的是,如果这足以证明使用普通的旧指针指针,是否还有更现代的工具或技术?我

在您的特定场景中,您可以使用类似的内容:

  1. 有一个名为ResourceLoader的类,其中包含std::map<ResourceId, std::weak_ptr<OpenGLResource> >,其中OpenGL资源是OpenGL资源使用的通用字符串。 ResourceID是用于标识特定资源(文件名,无论如何)
  2. 的任何内容
  3. 当您加载新资源ResourceLoader时,weak_ptr的检查地图会将其转换为shared_ptr并返回它们。如果地图中没有weak_ptr,或者它们为空,则会创建新的shared_ptr,将其weak_ptr推送到地图中,然后将其返回。

    Semi-c ++ peudocode(未经检查,很可能包含拼写错误和语法错误):

      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());
          }
      };  
    
  4. 如果想要实现资源丢失,只需遍历resourceMap,并在每个尚未过期的对象上调用reload。请参阅reloadAllResources

答案 2 :(得分: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来说无关紧要。此外,取消引用空指针具有明确定义的行为。