【问题标题】:Iterating over map and erasing element遍历地图并擦除元素
【发布时间】:2017-03-15 19:54:20
【问题描述】:

我有一个作为map 的全局变量和一个迭代此map 元素的函数,例如:

void printMap(){
    for ( auto it = MyMap.begin(); it != MyMap.end(); ++it  ){
        std::cout << it->second;
    }
}

效果很好。

我想为打印元素后的函数添加一个功能,它应该从map 中删除,如下所示:

void printMap(){
    for ( auto it = MyMap.begin(); it != MyMap.end(); ++it  ){
        std::cout << it->second;
        MyMap.erase(it);
    }
}

但是,通过添加擦除行,我得到了这种类型的异常错误:

线程 2:EXC_BAD_ACCESS(代码=1,地址=0x20000002)

我尝试了另一种方法,如下所示:

void myFunction(){
    printMap(); 
    MyMap.clear();
}

但我也遇到了同样的异常

线程 2:EXC_BAD_ACCESS(代码=1,地址=0x0)

据我了解,当我们引用不存在的内存位置时会发生这种异常。但我知道它就在那里,因为迭代器得到了它的值并被打印出来了。即便如此,我还是使用了第二种方法,以防万一我没有引用不存在的内存位置,但我仍然遇到了异常。

那么我怎样才能遍历元素打印结果然后删除它呢?

更新1
按照下面的建议和链接的主题,我将我的功能更改为:

void printMap(){
    bool i = true;
    for (auto it = MyMap.cbegin(), next_it = MyMap.cbegin(); it != MyMap.cend(); it = next_it)
    {
        cout << it->second;
        next_it = it; ++next_it;
        if (i) {
            MyMap.erase(it);
        }

    }
}

我也试过这个https://stackoverflow.com/a/42820005/7631183 和这个https://stackoverflow.com/a/42819986/7631183

问题仍然没有解决,我得到同样的错误




UPDATE2
我在另一台机器上运行相同的确切代码,它运行良好。我仍然不知道是什么原因,所以我猜想正如 cmets 中所建议的那样,std::map 第一个有一些问题。

附:第一台机器是mac,第二台是Linux

【问题讨论】:

标签: c++ c++11 std


【解决方案1】:

当你从地图中删除一个元素时,你已经使你在循环中使用的迭代器无效,从而导致错误。因为这个原因,erase 方法返回一个迭代器。

for( auto it = MyMap.begin(); it != MyMap.end(); )
{
    std::cout << it->second;
    it = MyMap.erase(it);
}

这确实是一个重复的问题。您只是对它的理解不够好,以至于无法看到它是重复的。我希望使迭代器无效的解释有助于澄清它。

【讨论】:

  • 当我尝试这个时,我得到了这个错误:线程 1 信号 sigabrt。我遵守了它然后再次运行我得到了旧错误。
  • 线程 1 信号中止很可能意味着线程中发生了未处理的异常,并且可能完全不相关。这就是为什么将您所要求的内容缩小到可能的最简单的测试用例并将该代码与问题一起发布很重要的原因。如果您创建一个新的控制台应用程序,创建一个 std::map,用元素填充它,然后使用给定的循环擦除,并且应用程序中没有其他代码,您将看到它如何擦除而没有错误。至于其他错误,我们不知道,因为我们无法想象没有发布或调试的代码中有什么。
  • 对于调试未处理的异常,您可以尝试在 Visual Studio 的异常对话框中启用异常中断,如果这恰好是您正在使用的 IDE。见msdn.microsoft.com/en-us/library/x85tt0dd.aspx
【解决方案2】:

在 C++11 及更高版本中,std:map::erase()iterator 返回到被擦除元素之后的元素。由于您使用的是auto,因此您使用的是C++11或更高版本,因此您可以在循环通过std::map时使用新的迭代器,例如:

void printMap(){
    auto it = MyMap.cbegin();
    while (it != MyMap.cend()) {
        std::cout << it->second;
        it = MyMap.erase(it);
    }
}

此外,由于您使用的是 C++11,因此您的第一个打印函数可以使用 range-for 循环来简化:

void printMap(){
    for ( auto &it: MyMap ){
        std::cout << it.second;
    }
}

【讨论】:

  • 我完全使用了这段代码,但我仍然遇到同样的错误
  • 那么,我猜你可能会迭代一个损坏的std::map。您是否尝试过How to remove from a map while iterating it? 中描述的其他成语?它们是否表现出相同的错误?
  • 那么您的std::map 很可能已损坏,因为这些是经过验证的惯用语,已知在正常条件下有效。
  • 好像是这样。地图是否有任何替代方案可以提高性能和内存?
  • @user7631183 我想你没抓住我的意思。你显然是在一个无效的std::map 上操作,你需要找出原因并修复它,而不是试图解决它。
猜你喜欢
  • 1970-01-01
  • 2013-12-06
  • 1970-01-01
  • 1970-01-01
  • 2016-02-22
  • 1970-01-01
  • 2014-04-12
  • 1970-01-01
  • 2022-01-21
相关资源
最近更新 更多