我正在尝试为我的游戏创建一个资源类(它使用了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);
}
我对移动语义没有太多经验,我不确定我是否把一切都搞定了。基本上,我错过了什么吗?如果这个问题不属于堆栈溢出,我很乐意将其移至相应的站点。
答案 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;
}
}