由於平時迭代器與向量用的並不是很多,因此今天上午遇到了一個非常怪異的問題,浪費了我整整4個小時!心疼呀!!
下面是詳細經過,不想看經過的可略過直接看我的總結。
我的項目需要處理非常復雜的數據結構,而且有很多結構都是自增長的,因此如果要想妥善的管理並處理這些數據就要有十幾個不同的動態數組支持才行,為了使代碼更加簡潔,因此打算使用向量來代替動態數據。
沒想到就是這個看似合理的選擇卻給我帶來了煩惱,在我調試到代碼最復雜的地方,正當我的大腦頻率與大腦緩存都異常吃緊時,突然彈出了一個讓我摸不到頭腦的錯誤,大腦直接宕機……
這個錯誤是“vector iterators incompatible”,提示我向量與迭代器不兼容,但是這很明顯是不可能的,我當時的代碼大致如下:
--------------------------------------------------------------------------------
....
....
typdef struct _STRUCT
{
....
....
vector<INFO> vecInfo;
}STRUCT;
STRUCT stcStruct;
....
....
for (vector<INFO>::iterator i= stcStruct.vecInfo.begin();
i != stcStruct.vecInfo.end();
i++) // 這裡報錯
{
.... www.2cto.com
....
}
--------------------------------------------------------------------------------
由代碼可知,我並沒有使用任何其他類型的向量,僅有INFO這一個類型,怎會出現這個錯誤呢,百思不得其解,跟進庫代碼暫時也沒有什麼收獲。
沒有辦法,想Google大叔求助吧,網上給出了以下幾種會引起此錯誤的情況,雖然對我沒用,但還是整理出來,方便各位查閱:
1、類型不匹配,例如用int型的向量迭代器與char型的向量迭代器進行比對操作。
2、比對時向量結構發生變化,比如以下代碼:
--------------------------------------------------------------------------------
for (vector<int>::iterator i= vector.begin();
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的風清月朗居