如下unordered_set的erase操作导致程序崩溃,crash。
#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;
}
原理分析:
用循环的方法删除内置范围的元素,这种做法是未定义的,也就是说产生未知的操作。
当你删除一个元素的时候,迭代器指向的元素已经被释放内存值,已经无效了,在这种情况下,编译器把当前的迭代器指向下一个元素,类似如下代码:
auto && __range = range-init;
for ( auto __begin = begin-expr(__range),
__end = end-expr(__range);
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
这个时候 ++__begin 被调用,元素被删除,迭代器是无效的。
正确的删除方法之一:
auto it = myset.begin();
while (it != myset.end()) { it = myset.erase(it); }
In C++11 erase方法返回新的指针 指向下一个有效的元素,避免在原来失效的迭代器上做增长。但是这里还有一点是,要想彻底清除内存值,需要调用clear函数。