unordered_map擦除段错误

K.C*_*hen 2 c++ segmentation-fault unordered-set

最近我发现了由erase方法引起的unordered_set这种奇怪的行为.我提出下面的最小例子.

首先,我创建一个unordered_set.然后我擦除其中一个元素,比如法国.然后我用for循环擦除每个元素.执行时,它会出现段错误.但是,如果我评论删除法国部分,那么代码工作正常.

这个程序是用编译的g++ test.cpp --std=c++11.g ++的版本是4.9.1.

#include <iostream>
#include <string>
#include <unordered_set>

int main ()
{
  std::unordered_set<std::string> myset =
  {"USA","Canada","France","UK","Japan","Germany","Italy"};

  // erasing by key, causing segfault later; no segfault if commented out
  myset.erase ( "France" );                         

  std::cout << "myset contains:";
  for ( const std::string& x: myset ) { myset.erase(x); }

  // The problem persists for a regular for loop as well. 
  //for (  std::unordered_set<std::string>::iterator it = myset.begin(); it!=myset.end(); it++  ) { myset.erase(it); }

  std::cout << std::endl;

  return 0;

}
Run Code Online (Sandbox Code Playgroud)

有人有线索吗?

谢谢,KC

Jon*_*ter 6

擦除基于范围的for循环内的元素是未定义的行为.擦除集合中的元素时,该元素的迭代器无效,并且在后台编译器使用当前元素的迭代器进入下一个元素.基于范围相当于:

auto && __range = range-init;
for ( auto __begin = begin-expr(__range),
   __end = end-expr(__range);
   __begin != __end;
   ++__begin ) {
   for-range-declaration = *__begin;
   statement
}
Run Code Online (Sandbox Code Playgroud)

++__begin调用时,元素已被擦除,迭代器无效.

编辑:这是一个如何正确执行此操作的示例:

auto it = myset.begin();
while (it != myset.end()) { it = myset.erase(it); }
Run Code Online (Sandbox Code Playgroud)

在C++ 11中,该erase方法返回一个新的迭代器,因此这可以避免在它指向的元素被擦除后递增旧的迭代器.但请注意,这段代码毫无意义,除非它只是一个实验.如果您只想清除一组内容,请致电myset.clear().