共享指针导致奇怪的行为

时间:2014-06-06 21:34:50

标签: c++ sfml

我在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

编辑:我完全知道删除精灵不会删除纹理,这会产生我必须处理的内存泄漏,这就是为什么我试图在第一个地方使用智能指针...

3 个答案:

答案 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游戏开发”,他们会很好地介绍这个主题。

http://www.packtpub.com/sfml-game-development/book

答案 2 :(得分:0)

sf::Sprite的对象非常轻量级(它实际上只是四元组的容器和更多信息),所以我甚至不愿意让它们在某种资源管理器中管理

更重的物体是纹理,所以只管理那个。

如前所述,纹理的智能指针超出范围,因此纹理被删除。

即使游戏中的每个实体都有自己的精灵,它也不会影响性能差(与重复使用一个精灵相比)。

因此,要解决您的问题,请根据路径管理纹理,而不是精灵。