我想有一个加载文件的函数(在这种情况下是一个OpenGL纹理),但实际上只加载一次文件,每次调用它之后它只返回它最初加载的文件。
这样做的好方法是什么?
感谢。
答案 0 :(得分:6)
您需要一些地方来存储该州。它既可以在对象内部,也可以作为静态变量。让我们说:
class TextureLoader {
public:
TextureLoader() {}
GLuint loadTexture(std::string const & filename){
std::map<std::string, GLuint>::iterator it = m_loadedTextures.find(filename);
if(it == m_loadedTextures.end()){
GLuint id = load(filename);
m_loadedTextures[filename] = id;
return id;
}
else{
return it->second;
}
}
~TextureLoader(){
// iterate and delete textures
}
private:
GLuint load(std::string const & filename){
// real loading
}
std::map<std::string, GLuint> m_loadedTextures;
};
答案 1 :(得分:4)
执行此操作的一种方法是在函数内部使用静态映射,该函数将参数与函数(此处为文件名)相关联,并指向其返回的唯一值。然后,您可以使用该函数检查地图是否包含输入,如果是,则返回与其关联的纹理。否则,您可以执行加载,将结果存储在地图中,然后交回结果。例如:
Texture* LoadTexture(const std::string& filename) {
static std::map<std::string, Texture*> previousResults;
/* Look up existing value. */
Texture* result = previousResults[filename];
/* If this doesn't exist, then go create it and pretend it was there all along. */
if (result == NULL)
result = previousResults[filename] = ActuallyLoadTexture(filename);
/* Hand back the cached result. */
return result;
}
如果这样做,您应该注意线程安全性,因为多次调用该函数可能会导致映射问题。适当地进行Syncrhonize。
答案 2 :(得分:2)
答案 3 :(得分:2)
通常,您可以将地图或unordered_map文件路径与Texture *相关联。
class render_state {
std::map<std::string, Texture> textures;
Texture* load_texture(std::string filepath) {
if (textures.find(filepath) != textures.end()) {
return &textures[filepath];
}
// load the texture here if it's not in cache
}
// Other rendering methods and state here.
};
但是现在,您还有另一个问题,即有时您可能会使用相对文件路径,有时甚至是绝对文件路径。此外,在某些库中,它们可以接受不同版本的换行符和反斜杠或正斜杠。如果我加载了纹理,然后仅在特定时间使用它并且不再需要它怎么办?哎呀,内存泄漏。
最好的办法就是返回一个Texture对象(或者(可能是智能的)指针)并让用户担心管理它。如果有人创建了资源,则他们的作业来管理它,而不是你的。
答案 4 :(得分:0)
见boost::flyweight。它几乎可以满足您的需求。加载对象避免重复。
答案 5 :(得分:0)
这是你想要的:
Texture& loadTexture(cosnt std::string& texture)
{
// Store all loaded data here
// Each file maps to a loded texture object
static boost::ptr_map<std::string, Texture> data;
boost::ptr_map<std::string, Texture>::iterator find = data.find(texture);
if (find == data.end())
{
// If it is not in the structure then load it this one time
find = data.insert(texture, doLoad(texture));
}
// return a reference to the texture
return *(find->second);
}