移动资源管理器类的语义

时间:2014-04-18 10:53:43

标签: c++ c++11 resources sfml move-semantics

我正在尝试为我的游戏创建一个资源类(它使用了SFML API)。 基本上我首先加载所需的资源,然后我在需要时获取对它们的引用,以避免资源类的繁重构造。

(我将使用sf :: Texture类作为示例)

问题在于加载功能。 为了制作一个sf :: Texture,我必须使用默认的构造函数,然后使用它的loadFromFile函数来获得所需的纹理。假设我有一个包含文件名对和相应资源的映射:

std::map<std::string, sf::Texture> textures;
sf::Texture texture;
texture.loadFromFile(file);

现在,如果我这样做:

textures.emplace(file, texture);

这将使用copy-constructor创建另一个sf :: Texture。 所以我认为我应该使用std :: move但显然sf :: Texture类没有移动构造函数,所以这仍然会复制。为了解决这个问题,我现在使用一个包含文件名对和对象的unique_pointers的映射。 所以我这样做:

std::unique_ptr<sf::Texture> texture(new sf::Texture);
texture->loadFromFile(file);
textures.emplace(file, std::move(texture));

以下是完整函数的外观:

void ResourceManager::loadTexture(std::string file)
{
        std::unique_ptr<sf::Texture> texture(new sf::Texture);
        if (!texture->loadFromFile(file))
        {
                throw std::runtime_error("ResourceManager::load - Failed to load " + file);
        }
        auto inserted = mtextures.emplace(file, std::move(texture));
        assert(inserted.second);
}

我对移动语义没有太多经验,我不确定我是否把一切都搞定了。基本上,我错过了什么吗?如果这个问题不属于堆栈溢出,我很乐意将其移至相应的站点。

2 个答案:

答案 0 :(得分:3)

您发布的代码看起来是正确的,给出了您正在尝试做的描述。

地图将被指定为资源的所有者。当它被销毁时,资源也将被销毁,除非有东西事先检索过资源(例如,通过std::move)。

唯一的建议是我在创建指针时使用std::make_unique(为了异常安全,并使代码更加惯用)。除了那个小细节,听起来你的想法是正确的。

答案 1 :(得分:1)

如果您担心自己无法有效移动sf::Texture,请不要移动sf::Texture。直接在地图中构建它们:

void ResourceManager::loadTexture(const std::string& file)
{
    assert(mtextures.find(file) == mtextures.end());
    auto& t = mtextures[file];
    try {
        if (!t.loadFromFile(file)) {
            throw std::runtime_error("ResourceManager::load - Failed to load " + file);
        }
    } catch(...) {
        mtextures.erase(file);
        throw;
    }
}