Правильное уничтожение указателей на std :: map
У меня есть карта, объявленная как
std::map<std::string, Texture*> textureMap;
который я использую для сопряжения пути к текстурному файлу с фактической текстурой, поэтому я могу ссылаться на текстуру по пути, не загружая одну и ту же текстуру кучу раз для отдельных спрайтов. То, что я не знаю, как это сделать, - это правильно уничтожить текстуры в деструкторе для класса ResourceManager (где находится карта).
Я думал об использовании цикла с итератором, как это:
ResourceManager::~ResourceManager()
{
for(std::map<std::string, Texture*>::iterator itr = textureMap.begin(); itr != textureMap.end(); itr++)
{
delete (*itr);
}
}
Но это не работает, он говорит, что удалить ожидаемый указатель. Это довольно поздно, поэтому я, вероятно, просто пропустил что-то очевидное, но я хотел, чтобы это работало перед сном. Так я закрываюсь, или я полностью не в том направлении?
Ответы
Ответ 1
Что касается вашего примера кода, вам нужно сделать это внутри цикла:
delete itr->second;
Карта состоит из двух элементов, и вам нужно удалить вторую. В вашем случае itr->first
является std::string
а itr->second
- Texture*
.
Если вам нужно удалить определенную запись, вы можете сделать что-то вроде этого:
std::map<std::string, Texture*>::iterator itr = textureMap.find("some/path.png");
if (itr != textureMap.end())
{
// found it - delete it
delete itr->second;
textureMap.erase(itr);
}
Вы должны убедиться, что запись существует на карте, иначе вы можете получить исключение при попытке удалить указатель текстуры.
Альтернативой может быть использование std::shared_ptr
вместо необработанного указателя, тогда вы можете использовать более простой синтаксис для удаления элемента с карты и позволить std::shared_ptr
обрабатывать удаление базового объекта, когда это необходимо. Таким образом, вы можете использовать erase()
с ключевым аргументом, например:
// map using shared_ptr
std::map<std::string, std::shared_ptr<Texture>> textureMap;
// ... delete an entry ...
textureMap.erase("some/path.png");
Это будет делать две вещи:
- Удалите запись с карты, если она существует
- Если нет других ссылок на
Texture*
, объект будет удален
Для использования std::shared_ptr
вам понадобится компилятор С++ 11 или Boost.
Ответ 2
Вы не используете правильный инструмент для работы.
Указатели не должны "владеть" данными.
boost::ptr_map<std::string, Texture>
используйте boost::ptr_map<std::string, Texture>
.
Ответ 3
Ответ не полностью касался проблемы с циклом. По крайней мере, Coverty (TM) не позволяет стереть итератор в цикле и по-прежнему использовать его для продолжения цикла. В любом случае, после удаления памяти, вызов clear() на карте должен сделать все остальное:
ResourceManager::~ResourceManager()
{
for(std::map<std::string, Texture*>::iterator itr = textureMap.begin(); itr != textureMap.end(); itr++)
{
delete (itr->second);
}
textureMap.clear();
}