【问题标题】:Properly destroying pointers in an std::map正确销毁 std::map 中的指针
【发布时间】:2013-11-27 01:01:56
【问题描述】:

我有一张地图声明为

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

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

【问题讨论】:

    标签: c++ pointers stl destructor


    【解决方案1】:

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

    delete itr->second;
    

    地图有两个元素,您需要删除第二个元素。在您的情况下,itr-&gt;firststd::stringitr-&gt;secondTexture*

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

    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,您要么需要最新的 C++11 编译器,要么需要 Boost

    【讨论】:

    • 太棒了。在明确说明要删除的地图中的值时,您是否也必须这样做?意思是delete textureMap["some/path.png"] 工作还是你也必须做delete textureMap["some/path.png"].second
    • 我们可以使用 clear() 方法一次性删除元素,而不是使用迭代器逐个删除元素。无论如何,我们必须将纹理指针一一删除。
    • @Mike。您可以执行“delete textureMap["some/path.png"]" 来删除对象,但请记住,密钥仍会映射到该地址,因此您也必须对此进行处理。
    • @Subhajit 我知道你的意思,但我认为你使用“删除”这个词可能会让一些人感到困惑。
    • @HappyCoder 不,因为它不会删除迭代器本身,它只是删除迭代器指向的东西。它正在删除Texture*
    【解决方案2】:

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

    指针不应“拥有”数据。

    请改用boost::ptr_map&lt;std::string, Texture&gt;

    【讨论】:

    • (或在 C++11 中 std::map&lt;std::string, std::unique_ptr&lt;Texture&gt;&gt;,如果您愿意/必须保持标准)
    • 一旦您创建了动态应用程序,指针将拥有数据。你甚至无法避免这种情况。
    【解决方案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();
    }
    

    【讨论】:

    • textureMap.clear(); 已过时,因为 textureMap 析构函数会自动执行此操作。
    猜你喜欢
    • 2012-11-30
    • 2013-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-05
    • 2012-04-27
    • 2019-03-01
    相关资源
    最近更新 更多