C ++: заставить метод возвращать один и тот же объект каждый раз - PullRequest
2 голосов
/ 04 января 2011

Я хотел бы иметь функцию, которая загружает файл (в данном случае текстуру OpenGL), но на самом деле загружает файл только один раз, и каждый раз, когда он вызывается, он просто возвращает то, что изначально загрузил.

Какой хороший способ сделать это?

Спасибо.

Ответы [ 6 ]

6 голосов
/ 04 января 2011

Вам нужно место для хранения этого состояния.Это может быть либо внутри объекта, либо в виде статической переменной.Допустим,

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;
};
4 голосов
/ 04 января 2011

Одним из способов сделать это было бы иметь статическую карту внутри функции, которая связывает параметры функции (здесь имя файла) с указателем на уникальное значение, которое она возвращает.Затем можно заставить функцию проверить, содержит ли карта входные данные, и, если это так, вернуть текстуру, связанную с ней.В противном случае вы можете выполнить загрузку, сохранить результат на карте и вернуть результат обратно.Например:

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;
}

Если вы сделаете это, вы должны быть осторожны с безопасностью потоков, поскольку множественные вызовы функции могут вызвать проблемы с картой.Синхронизируйте при необходимости.

2 голосов
/ 04 января 2011

Как правило, вы связываетесь с картой или путями файла unordered_map с текстурой * s.

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.
};

Но теперь у вас есть другая проблема: иногда вы можете использовать относительный путь к файлу, а иногда абсолютный путь к файлу. Кроме того, в некоторых библиотеках они могут принимать различные версии новой строки и обратной косой черты или прямой косой черты. Что если я загрузил текстуру, а затем использовал ее только в течение определенного времени и больше не нуждался? Упс, утечка памяти.

Лучше всего просто вернуть объект текстуры (или (возможно, умный) указатель на него) и позволить пользователю беспокоиться об управлении им. Если кто-то создает ресурс, управлять им будет , а не вашим.

2 голосов
/ 04 января 2011

Похоже, вы ищете реализацию шаблона проектирования Singleton .

Существует множество способов реализовать это, и теперь, когда вы знаете, что это такоеназывается, вы можете решить, какой метод лучше.Ваша первая остановка может быть поиск этого сайта для других подобных вопросов.

0 голосов
/ 04 января 2011

Будет ли это то, что вы ищете:

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);
}
0 голосов
/ 04 января 2011

См. boost :: flyweight . Это делает в значительной степени то, что вы хотите. Загружать объекты, избегая дубликатов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...