我一直在为 SFML2 精灵制作一个简单的精灵缓存。我有一个管理器类,其中包含指向精灵的指针映射。而且我还有一个精灵类,它包含对其所有者地图的引用。现在问题在于精灵的析构函数。它看起来像这样:
~ActualSprite()
{
if(m_iteratorLocation != m_ownerMap.end())
{
m_ownerMap.erase(m_iteratorLocation);
}
}
m_iteratorLocation 应该是精灵地图中精灵的当前位置。它在精灵构造函数中初始化,这是精灵管理器的精灵创建方法
SpritePtr getSprite(SpriteId name)
{
if(!spriteMap[name])
{
spriteMap[name] = std::tr1::make_shared< ActualSprite >(spriteMap, spriteMap.find(name));
clipSprite(name);
return spriteMap[name];
}
else
return spriteMap[name];
}
基本上,当我退出程序时,我会收到一条异常/错误消息,说明:Expression: map/set iterator outside range
.
起初我认为发生这种情况是因为spriteMap.find(name)
找不到名称并返回spriteMap.end()
。但我不明白,不是第一次提到spriteMap[name]
将name
密钥添加到地图吗?无论如何,然后我添加了 if 语句,仅在迭代器不等于 .end() 时才删除映射条目,但它仍然会弹出。
基本上现在我使用名称枚举而不是迭代器进行擦除并且它可以工作,但我仍然想知道为什么我会收到错误消息。
这是当前工作版本的完整代码,以及引发错误的注释迭代器版本。
#include <SFML/Graphics.hpp>
#include <memory>
#include <map>
enum SpriteId
{
ITEM1,
ITEM2,
ITEM3,
ITEM4,
ITEM5
};
const int WIDTH = 100;
const int HEIGHT = 100;
class ActualSprite;
typedef std::tr1::shared_ptr< ActualSprite > SpritePtr;
typedef std::map< SpriteId, SpritePtr > SpriteMap;
class ActualSprite : public sf::Sprite
{
private:
//SpriteMap::iterator m_iteratorLocation;
SpriteMap &m_ownerMap;
SpriteId &m_name;
public:
//ActualSprite(SpriteMap &ownerMap, SpriteMap::iterator iteratorLocation) : m_ownerMap(ownerMap), m_iteratorLocation(iteratorLocation)
//{}
ActualSprite(SpriteMap &ownerMap, SpriteId &name) : m_ownerMap(ownerMap), m_name(name)
{}
~ActualSprite()
{
m_ownerMap.erase(m_name);
}
//~ActualSprite()
//{
// if(m_iteratorLocation != m_ownerMap.end())
// {
// m_ownerMap.erase(m_iteratorLocation);
// }
//}
};
class SpriteManager
{
private:
SpriteMap spriteMap;
sf::Texture& m_texture;
void clipSprite(SpriteId name)
{
spriteMap.at(name)->setTexture(m_texture);
switch(name)
{
case ITEM1: spriteMap.at(name)->setTextureRect(sf::IntRect(0,0,WIDTH,HEIGHT));break;
case ITEM2: spriteMap.at(name)->setTextureRect(sf::IntRect((1*WIDTH),0,WIDTH,HEIGHT));break;
case ITEM3: spriteMap.at(name)->setTextureRect(sf::IntRect((2*WIDTH),0,WIDTH,HEIGHT));break;
case ITEM4: spriteMap.at(name)->setTextureRect(sf::IntRect((3*WIDTH),0,WIDTH,HEIGHT));break;
case ITEM5: spriteMap.at(name)->setTextureRect(sf::IntRect((4*WIDTH),0,WIDTH,HEIGHT));break;
//default: exception or somethin'
}
}
public:
SpriteManager(sf::Texture& texture) : m_texture(texture)
{}
SpritePtr getSprite(SpriteId name)
{
if(!spriteMap[name])
{
spriteMap[name] = std::tr1::make_shared< ActualSprite >(spriteMap, name);
/*spriteMap[name] = std::tr1::make_shared< ActualSprite >(spriteMap, spriteMap.find(name));*/
clipSprite(name);
return spriteMap[name];
}
else
return spriteMap[name];
}
};
int main()
{
sf::RenderWindow window(sf::VideoMode(800,600), "Test", sf::Style::Titlebar | sf::Style::Close);
sf::RectangleShape background(sf::Vector2f(800.0f,600.0f));
window.setFramerateLimit(30);
sf::Texture spriteSheet;
if(!spriteSheet.loadFromFile("SpriteSheet.png"))
{
return 1;
}
SpriteManager sprites(spriteSheet);
SpritePtr sprite = sprites.getSprite(ITEM2);
SpritePtr sprite2 = sprites.getSprite(ITEM4);
sprite->setPosition(100,100);
sprite2->setPosition(200,100);
while(window.isOpen())
{
sf::Event event;
while( window.pollEvent(event))
{
if(sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
sf::Vector2i currentPos = sf::Mouse::getPosition(window);
sprite->setPosition((static_cast<float>(currentPos.x) - (WIDTH/2)), (static_cast<float>(currentPos.y) - (HEIGHT/2)));
}
if(event.type == sf::Event::Closed)
{
window.close();
}
}
window.clear();
window.draw(background);
window.draw(*sprite);
window.draw(*sprite2);
window.display();
}
return 0;
}
注意:这只是一个测试,所以这就是为什么所有内容都在一个 .cpp 文件中以及为什么项目名称不是描述性的。