原文链接:http://bingxinye1.blog.163.com/blog/static/168797098201332294321491/
好不容易放弃了map,改用了vector,结果又出现了这个。纠结了一晚上了。。。大致是要放弃了。
发现引发这个错误的代码如下:
for (VectorType::iterator it = someVector.begin();; it != someVector.end();++it;)
{
if (*it== value)
{
someVector.erase(it);
}
}
代码中,在erase操作后,没有修改it就继续循环,在与end()比较时,断言出现。
这里的主要问题是,vector可以用任意方法实现erase,不保证在erase一个元素后,后续的元素一定被移动到这个iterator所引用的位置(地址)。当然,这在几乎所有STL的实现中,都是对的,这也就是以前用VC6编译后运行没有问题的原因。但如果这里用的不是vector,而是list或是map,运行到这里,程序会毫不犹豫的崩溃。
正确的做法是这样的:
STL里所有的容器类的erase实现都会返回一个iterator,这个iterator指向了“当前删除元素的后继元素,或是end()”
因此,在遍历容器的所有元素过程中通过erase删除一个元素后,将erase的返回值赋给迭代变量:
for (VectorType::iterator it = someVector.begin();; it != someVector.end();)
{
if (*it== value)
{
it = someVector.erase(it);
}
else
{
++it;
}
}
P.S. 可以看出,VS2005带的STL增加了更多的调试特性以避免出现STL的一些错误,有条件的话最好用VS2005的STL。如果没有VS2005,也可以使用STLport,STLport在调试特性上也非常出色。
如果你要略过这个检查,可以用#define _HAS_ITERATOR_DEBUGGING 0 不过建议还是检查线程的同步代码。
2.空Vector问题。不允许引用空vector的begin迭代器,因为vector是空的,自然不会有第一个项目,使用也会引发vector iterators incompatible。
3.vector同时读写引发。vc2005 对于迭代器的匹配是非常严格的,通常这种错误是因为两个不同的迭代器操作同一个 vector,或者是因为迭代器在遍历vector时,vector的链表改变了,就会引发这种错误,比如vector在遍历的途中,别的位置push_back()一个元素,这时迭代器就失效了,导致错误。可以使用临界区互斥访问。
4.迭代器越界,则相应会调用一个非法参数处理程序。
再次提醒,可以通过抛出一个越界异常来避免产生非法参数问题。在代码中加入#define value of _SECURE_SCL_THROWS,并把value值设为1,这样就不会调用非法参数处理程序,而是产生一个异常了。
也可以通过设置#defined value of _SECURE_SCL值为零,关闭此迭代器检查,通常默认情况下,此选项是打开的。
5.VS2005编译Release版STL的迭代器bug。经测试Unicode版的比较容易出这个问题,就是莫名其妙的迭代器错误。
微软的原文:The bug afflicted all Standard containers (vector, deque, list, set, multiset, map, multimap, and string) when _HAS_ITERATOR_DEBUGGING was disabled and _SECURE_SCL was enabled. Additionally, deque was afflicted when both were disabled.解决办法是
#ifndef _DEBUG
#define _SECURE_SCL 0
#endif