总结:结构体里面有vector等成员时,不要用memset清零(从库的跟踪中我发现向量是使用名称为“_Myproxy”、“_Mynextiter”这两个指针来寻找与之相邻的值的,在我们定义一个向量时,它便初始化一个“_Myproxy”,而我的代码却在类的构造函数中对定义的结构体执行了一个清零的操作)
由于平时迭代器与向量用的并不是很多,因此今天上午遇到了一个非常怪异的问题,浪费了我整整4个小时!心疼呀!!下面是详细经过,不想看经过的可略过直接看我的总结。 我的项目需要处理非常复杂的数据结构,而且有很多结构都是自增长的,因此如果要想妥善的管理并处理这些数据就要有十几个不同的动态数组支持才行,为了使代码更加简洁,因此打算使用向量来代替动态数据。 没想到就是这个看似合理的选择却给我带来了烦恼,在我调试到代码最复杂的地方,正当我的大脑频率与大脑缓存都异常吃紧时,突然弹出了一个让我摸不到头脑的错误,大脑直接宕机……
这个错误是“vector iterators incompatible”,提示我向量与迭代器不兼容,但是这很明显是不可能的,我当时的代码大致如下:
--------------------------------------------------------------------------------
....
....
typdef struct _STRUCT
{
....
....
vector
}STRUCT;
STRUCT stcStruct;
....
....
for (vector
i != stcStruct.vecInfo.end();
i++) // 这里报错
{
.... www.2cto.com
....
}
--------------------------------------------------------------------------------
由代码可知,我并没有使用任何其他类型的向量,仅有INFO这一个类型,怎会出现这个错误呢,百思不得其解,跟进库代码暂时也没有什么收获。
没有办法,想Google大叔求助吧,网上给出了以下几种会引起此错误的情况,虽然对我没用,但还是整理出来,方便各位查阅:
1、类型不匹配,例如用int型的向量迭代器与char型的向量迭代器进行比对操作。
2、比对时向量结构发生变化,比如以下代码:
--------------------------------------------------------------------------------
for (vector
i != vector.end();
i++) // 这里报错
{
vector.erase(i);
....
}
--------------------------------------------------------------------------------
在erase操作后,没有将循环变量i指向修改后的向量迭代器,就继续循环,再与end()比较时断言出现。
解决方法是将“vector.erase(i);”替换为“i = vector.erase(i);”,这是因为STL里的所有容器类中的erase实现都会返回一个迭代器,这个迭代器指向了“当前删除元素的后继元素,或是end()”。
除了以上两条,在也没有其他解释了,无奈之后再次尝试跟进库代码,在向量类的不等号重载中跟到了以下代码中,而后发现玄机……
--------------------------------------------------------------------------------
void _Compat(const _Myiter& _Right) const
{ // test for compatible iterator pair
if (this->_Getcont() == 0 // 判断_Myproxy是否为0,为0则报错,否则获取所属容器
|| this->_Getcont() != _Right._Getcont()) // 判断两个向量的型类是否一致
{ // report error
_DEBUG_ERROR("vector iterators incompatible");
_SCL_SECURE_INVALID_ARGUMENT;
}
}
--------------------------------------------------------------------------------
我们在跟进_Getcont(),_Getcont()代码如下:
--------------------------------------------------------------------------------
const _Container_base12 *_Getcont() const
{ // get owning container
return (_Myproxy == 0 ? 0 : _Myproxy->_Mycont);
}
--------------------------------------------------------------------------------
在这里我发现我那段代码中的_Myproxy是为0的,也就是说我们的类型应该不存在问题,而是向量的“链条”断掉了。
从库的跟踪中我发现向量是使用名称为“_Myproxy”、“_Mynextiter”这两个指针来寻找与之相邻的值的,在我们定义一个向量时,它便初始化一个“_Myproxy”,而我的代码却在类的构造函数中对定义的结构体执行了一个清零的操作:
ZeroMemory(&m_stcStruct, sizeof(STRUCT));
从而导致了向量中的“_Myproxy”丢失,虽然仍可以对其进行push_back()等其他几乎一切操作,但是这个向量缺唯独不能执行遍历者一种操作,多么隐晦的一个错误呀……
总结,写代码时不忘初始化自己构造出来的玩意是个好习惯,但也要注意不要滥竽充数,懂得东西随便怎么操作都可以,如果是不懂的东西,还是先了解一下为好。
要时刻对你眼前的电脑保持一颗敬畏的心……
摘自:A1Pass的风清月朗居