简体   繁体   English

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

[英]Alternatives to pointer-to-pointers in C++?

I find myself at a few places in my game wanting to use pointer-to-pointer in my design. 我发现自己在游戏中的几个地方想要在我的设计中使用指针指针。 For example, I have a class OpenGLRenderer which creates meshes given vertex/indice/texcoord data, materials given material props, etc. and then a class ResourceManifest which caches meshes/materials from file and upon loading one of these resources creates an instance of it using the OpenGLRenderer . 例如,我有一个类OpenGLRenderer ,它创建给定顶点/ indice / texcoord数据的网格,给定材料道具的材料等,然后是一个类ResourceManifest ,它从文件中缓存网格/材料,并在加载其中一个资源时创建它的一个实例使用OpenGLRenderer So there is a coupling there. 所以那里有一个耦合。

I typically like to employ RAII design when coding which tempts me to the following relationship: 我通常喜欢在编码时使用RAII设计,这会诱使我遵循以下关系:

ResourceManifest(OpenGLRenderer** renderer);

Because when the OpenGL context has been torn down and all OpenGL state-specific stuff needs to be reinitialized, such as when recreating the window, I just recreate the OpenGLRenderer and let the constructor/destructor do all the work and ResourceManifest using it will never be the wiser. 因为当OpenGL上下文被拆除并且所有OpenGL状态特定的东西需要重新初始化时,例如重新创建窗口时,我只是重新创建OpenGLRenderer并让构造函数/析构函数完成所有工作,而使用它的ResourceManifest将永远不会更聪明。

What I am wondering is if this is enough justification of using plain old pointer-to-pointers, are there any more modern tools or techniques available? 我想知道的是,如果这足以证明使用普通的旧指针指针,是否还有更现代的工具或技术? I've been looking at various smart_ptrs for example, but they do not deal with the problem at hand, as I want to recreate the managed object without passing out new smart_ptrs. 我一直在寻找各种smart_ptrs,但他们并没有处理手头的问题,因为我想重新创建托管对象而不会传递新的smart_ptrs。

As others have already stated, you could reference a smart pointer. 正如其他人已经说过的那样,你可以引用一个智能指针。

However, if you also want to provide functionality beyond smart pointerness you could make your code into an iterator especially if the underlying data structures are not homogeneous. 但是,如果您还希望提供智能指针之外的功能,则可以将代码转换为迭代器,尤其是在底层数据结构不同的情况下。 Again, this is a matter of how you'll use your pointer to pointer. 同样,这是你如何使用指针指针的问题。 Then whatever interface you finally use could itself be wrapped in a smart pointer. 那么你最终使用的任何接口本身都可以用智能指针包装。

What I am wondering is if this is enough justification of using plain old pointer-to-pointers, are there any more modern tools or techniques available? 我想知道的是,如果这足以证明使用普通的旧指针指针,是否还有更现代的工具或技术? I 一世

In your particular scenario, you could use something like that: 在您的特定场景中,您可以使用类似的东西:

  1. There is a class called ResourceLoader which contains std::map<ResourceId, std::weak_ptr<OpenGLResource> > where OpenGL resource is generic clas used by OpenGL resources. 有一个名为ResourceLoader的类,它包含std::map<ResourceId, std::weak_ptr<OpenGLResource> > ,其中OpenGL资源是OpenGL资源使用的通用clas。 ResourceID is whatever you use to identify specific resource (filename, whatever) ResourceID是用于标识特定资源的任何内容(文件名,等等)
  2. When you load new resource ResourceLoader checks map for weak_ptr 's converts them to shared_ptr and returns them. 当您加载新资源时, ResourceLoader检查weak_ptr的映射将它们转换为shared_ptr并返回它们。 If there are no weak_ptr s in map, or if they're NULL, he creates new shared_ptr , pushes its weak_ptr into map, and returns it. 如果map中没有weak_ptr ,或者它们是NULL,则创建新的shared_ptr ,将其weak_ptr推送到map中,然后返回它。

    Semi-c++ peudocode (unchecked, most likely contains typos and syntax errors): 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()); } }; 
  3. When you want to realod lost resources, you simply iterate through resourceMap, and call reload on every object that hasn't expired. 当您想要实现丢失资源时,只需遍历resourceMap,并在每个尚未过期的对象上调用reload。 See reloadAllResources 请参阅reloadAllResources

I am not even sure I fully understand your question, but let me give it a shot: could you use std::weak_ptr ? 我甚至不确定我完全理解你的问题,但让我std::weak_ptr :你能用std::weak_ptr吗?

Consider the following (contrived) example: 考虑以下(人为的)示例:

#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();

}

Compiled as: g++ example.cpp -std=c++11 (gcc 4.7.2). 编译为: g++ example.cpp -std=c++11 (gcc 4.7.2)。 Output: 输出:

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

The purpose of std::weak_ptr is to share a pointer without sharing ownership. std::weak_ptr的目的是共享指针而不共享所有权。 So you could reset or completely recreate your Renderer , and it would be immaterial to Context . 因此,您可以重置或完全重新创建Renderer ,这对Context来说并不重要。 Also, dereferencing to a null pointer has well-defined behavior. 此外,取消引用空指针具有明确定义的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM