C++ 正确销毁 std::map 中的指针

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19970531/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 23:17:50  来源:igfitidea点击:

Properly destroying pointers in an std::map

c++pointersstldestructor

提问by Mike

I have a map declared as

我有一张地图声明为

std::map<std::string, Texture*> textureMap;

which I use for pairing the path to a texture file to the actual texture so I can reference the texture by the path without loading the same texture a bunch of times for individual sprites. What I don't know how to do is properly destroy the textures in the destructor for the ResourceManager class (where the map is).

我用于将纹理文件的路径与实际纹理配对,这样我就可以通过路径引用纹理,而无需为单个精灵多次加载相同的纹理。我不知道该怎么做是在 ResourceManager 类(地图所在的位置)的析构函数中正确销毁纹理。

I thought about using a loop with an iterator like this:

我想过使用循环和这样的迭代器:

ResourceManager::~ResourceManager()
{
    for(std::map<std::string, Texture*>::iterator itr = textureMap.begin(); itr != textureMap.end(); itr++)
    {
        delete (*itr);
    }
}

But that doesn't work, it says delete expected a pointer. It's pretty late so I'm probably just missing something obvious, but I wanted to get this working before bed. So am I close or am I totally in the wrong direction with this?

但这不起作用,它说删除需要一个指针。现在已经很晚了,所以我可能只是遗漏了一些明显的东西,但我想在睡觉前完成这项工作。那么我是关闭还是完全错误的方向?

回答by Roger Rowland

As far as your sample code goes, you need to do this inside the loop:

就您的示例代码而言,您需要在循环内执行此操作:

delete itr->second;

The map has two elements and you need to delete the second. In your case, itr->firstis a std::stringand itr->secondis a Texture*.

地图有两个元素,您需要删除第二个。在您的情况下,itr->firstis astd::stringitr->secondis a Texture*

If you need to delete a particular entry, you could do something like this:

如果您需要删除特定条目,您可以执行以下操作:

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);
}

You have to make sure that the entry exists in the map otherwise you may get an exception when trying to delete the texture pointer.

您必须确保该条目存在于地图中,否则在尝试删除纹理指针时可能会出现异常。

An alternative might be to use std::shared_ptrinstead of a raw pointer, then you coulduse a simpler syntax for removing an item from the map and let the std::shared_ptrhandle the deletion of the underlying object when appropriate. That way, you can use erase()with a key argument, like so:

另一种方法可能是使用std::shared_ptr而不是原始指针,然后您可以使用更简单的语法从地图中删除项目,并std::shared_ptr在适当的时候让处理底层对象的删除。这样,您可以使用erase()key 参数,如下所示:

// map using shared_ptr
std::map<std::string, std::shared_ptr<Texture>> textureMap;

// ... delete an entry ...
textureMap.erase("some/path.png");

That will do two things:

这将做两件事:

  • Remove the entry from the map, if it exists
  • If there are no other references to the Texture*, the object will be deleted
  • 从地图中删除条目(如果存在)
  • 如果没有其他对 的引用,则Texture*该对象将被删除

In order to use std::shared_ptryou'll either need a recent C++11 compiler, or Boost.

为了使用,std::shared_ptr你需要一个最新的 C++11 编译器,或者Boost

回答by charo

The answer didn't fully address the looping issue. At least Coverty (TM) doesn't allow erasing the iterator within the loop and still use it to continue looping. Anyway, after deleting the memory, calling clear() on the map should do the rest:

答案并没有完全解决循环问题。至少 Coverty (TM) 不允许擦除循环内的迭代器并仍然使用它来继续循环。无论如何,删除内存后,在地图上调用 clear() 应该完成剩下的工作:

ResourceManager::~ResourceManager()
{
    for(std::map<std::string, Texture*>::iterator itr = textureMap.begin(); itr != textureMap.end(); itr++)
    {
        delete (itr->second);
    }
    textureMap.clear();
}

回答by user541686

You're not using the right tool for the job.

您没有使用正确的工具来完成这项工作。

Pointers should not "own" data.

指针不应该“拥有”数据。

Use boost::ptr_map<std::string, Texture>instead.

使用boost::ptr_map<std::string, Texture>来代替。