我发现自己在游戏中的几个地方想要在我的设计中使用指针指针。例如,我有一个类OpenGLRenderer
,它创建给定顶点/ indice / texcoord数据的网格,给定材质道具的材料等,然后是一个类ResourceManifest
,它从文件中缓存网格/材料,并在加载一个这些资源使用OpenGLRenderer
创建它的实例。所以那里有一个耦合。
我通常喜欢在编码时使用RAII设计,这会让我想到以下关系:
ResourceManifest(OpenGLRenderer** renderer);
因为当OpenGL上下文被拆除并且所有OpenGL状态特定的东西需要重新初始化时,例如重新创建窗口时,我只是重新创建OpenGLRenderer
并让构造函数/析构函数完成所有工作ResourceManifest
使用它永远不会更聪明。
我想知道的是,如果这足以证明使用普通的旧指针指针,是否还有更现代的工具或技术?我一直在寻找各种smart_ptrs,但他们并没有处理手头的问题,因为我想重新创建托管对象而不会传递新的smart_ptrs。
答案 0 :(得分:3)
正如其他人已经说过的那样,你可以引用智能指针。
但是,如果您还希望提供智能指针之外的功能,则可以将代码转换为迭代器,尤其是在底层数据结构不同的情况下。同样,这是你如何使用指针指针的问题。然后,你最终使用的任何接口本身都可以用智能指针包装。
答案 1 :(得分:1)
我想知道的是,如果这足以证明使用普通的旧指针指针,是否还有更现代的工具或技术?我
在您的特定场景中,您可以使用类似的内容:
ResourceLoader
的类,其中包含std::map<ResourceId, std::weak_ptr<OpenGLResource> >
,其中OpenGL资源是OpenGL资源使用的通用字符串。 ResourceID是用于标识特定资源(文件名,无论如何)当您加载新资源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());
}
};
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
来说无关紧要。此外,取消引用空指针具有明确定义的行为。