我在SFML 2.1中有以下代码
类ResourceManager:
shared_ptr<Sprite> ResourceManager::getSprite(string name) {
shared_ptr<Texture> texture(new Texture);
if(!texture->loadFromFile(resPath+spritesPath+name))
throw new NotSuchFileException();
shared_ptr<Sprite> sprite(new Sprite(*texture));
return sprite;
}
主要方法:(我将省略大部分不相关的代码
shared_ptr<Sprite> sprite = ResourceManager::getSprite("sprite.png");
...
while(renderWindow.isOpen())
renderWindow.draw(*sprite);
奇怪的是,这使我的精灵渲染完全变白,但如果我这样做:
shared_ptr<Sprite> ResourceManager::getSprite(string name) {
Texture* texture = new Texture; // <------- From shared pointer to pointer
if(!texture->loadFromFile(resPath+spritesPath+name))
throw new NotSuchFileException();
shared_ptr<Sprite> sprite(new Sprite(*texture));
return sprite;
}
效果很好。
那么这里发生了什么?我假设共享指针只能用作指针。它会被删除吗?我的主要方法是保留对它的引用,所以我真的不明白这里发生了什么:S
编辑:我完全知道删除精灵不会删除纹理,这会产生我必须处理的内存泄漏,这就是为什么我试图在第一个地方使用智能指针...答案 0 :(得分:5)
我可能会离开这里,但我认为值得一试:
如果sprite类构造函数采用常规Texture *或Texture引用(而不是采用和存储共享指针),那么当shared_ptr超出getSprite中的范围时,纹理将被销毁(因为没有shared_ptr到纹理存在于那一点之后)。
答案 1 :(得分:1)
第一个中的共享指针超出范围并删除对已加载纹理的引用。你需要保存对sf :: Texture实例的引用以保留实例,所以你想要这样的东西(未经测试的代码):
std::map<std::string, std::unique_ptr<sf::Texture>> mLoadedTextures;
std::shared_ptr<sf::Sprite> ResourceManager::getSprite(std::string name) {
auto found = mLoadedTextures.find(name);
if (found == mLoadedTextures.end()) {
std::unique_ptr<sf::Texture> texture(new sf::Texture());
if (!texture->loadFromFile(resPath+spritesPath+name)) {
// ERROR: Unable to find/load texture
}
auto inserted = mLoadedTextures.insert(std::make_pair(name, std::move(texture)));
if (!inserted.second)) {
// ERROR: Unable to insert into map
}
found = inserted.first;
}
shared_ptr<sf::Sprite> sprite(new sf::Sprite(*found.second));
return sprite;
}
但是,您应该重新考虑ResourceManager的运行方式。理想情况下,您可以预先完成所有加载,并将所有这些纹理放在资源管理器拥有的地图中。然后创建一个精灵将不必在“关键路径上”加载纹理的性能损失。
如果您阅读“SFML游戏开发”,他们会很好地介绍这个主题。
答案 2 :(得分:0)
sf::Sprite
的对象非常轻量级(它实际上只是四元组的容器和更多信息),所以我甚至不愿意让它们在某种资源管理器中管理
更重的物体是纹理,所以只管理那个。
如前所述,纹理的智能指针超出范围,因此纹理被删除。
即使游戏中的每个实体都有自己的精灵,它也不会影响性能差(与重复使用一个精灵相比)。
因此,要解决您的问题,请根据路径管理纹理,而不是精灵。