Vector的erase成員函數有許多容易導致問題的情況.其中以迭代器失效問題最為常見.
關於迭代器的失效問題,以及erase如何刪除vector中指定值(可能不止一個),我曾今也對erase的使用方式和內容結合起來寫過一些字.
博文地址:http://blog.csdn.net/yuanweihuayan/article/details/6790516
似乎對於刪除的解析已經夠全面了.可是最近在項目裡面發現一個很奇怪的問題,跟蹤了很久都沒有發現是什麼問題導致的.
今天知道了問題的原因,但是為什麼會這樣,我還是不清楚.看來STL這塊還需加大力度學習它.
源碼如下:
struct Usr{string strUiD;string strSrnName;string strNickName; string strDesc; string strGender; string strIcon; string strVtitle; string strVType; Usr(){ strUiD = "";strSrnName = "";strNickName = "";strDesc = "";strGender = "";strIcon = "";strVtitle = "";strVType = "";}Usr( string strUid,string strSrnName,string strNickName ){SetData( strUid,strSrnName,strNickName );}void SetData( string strUid,string strSrnName,string strNickName ){this->strUiD = strUid;this->strSrnName = strSrnName;this->strNickName = strNickName;strDesc = "";strGender = "";strIcon = "";strVtitle = "";strVType = "";}void operator=( const Usr& usr ){if ( usr.strUiD == strUiD){return;}strSrnName = usr.strSrnName;strNickName = usr.strNickName;strDesc = usr.strDesc;strGender = usr.strGender;strIcon = usr.strIcon;strVtitle = usr.strVtitle;strVType = usr.strVType;}bool operator==( Usr& usr ){if ( usr.strUiD == strUiD ){return true;}return false;}bool isEqual( Usr usr ){if ( usr.strUiD == strUiD ){return true;}return false;}};vector<Usr> vecUsr;Usr usr( "10001","ysl","袁孫良" );vecUsr.push_back( usr );usr.SetData( "10002","zxy","張學友" );vecUsr.push_back( usr );usr.SetData( "10003","ldh","劉德華" );vecUsr.push_back( usr );for ( vector<Usr>::iterator iterUsr = vecUsr.begin();iterUsr != vecUsr.end();iterUsr ++ ){if ( iterUsr->strUiD == "10001" ){vector<Usr>::iterator iterEnd = vecUsr.erase( iterUsr );if ( iterEnd != vecUsr.end() ){TRACE("success");break;}}}TRACE( "\n***************************************************************\n" );for ( vector<Usr>::iterator iterTemp= vecUsr.begin();iterTemp != vecUsr.end();iterTemp ++ ){CString strFormat;strFormat.Format( "編號:%s, 暱稱:%s\n",iterTemp->strUiD.c_str(),iterTemp->strNickName.c_str() );TRACE( strFormat.GetBuffer() );}
先看輸出結果:
success
***************************************************************
編號:10001, 暱稱:張學友
編號:10002, 暱稱:劉德華
這個結果很令人費解.
strUiD好像整體往下"移動"一位
採用單步調試或者TRACE來檢查程式的資料情況,(這裡我採用TRACE,原因很簡單,單步調試對迭代器不起啥作用).
加入的調試資訊如下:
vector<Usr> vecUsr;Usr usr( "10001","ysl","袁孫良" );vecUsr.push_back( usr );usr.SetData( "10002","zxy","張學友" );vecUsr.push_back( usr );usr.SetData( "10003","ldh","劉德華" );vecUsr.push_back( usr );TRACE( "\n***************************************************************\n" );for ( vector<Usr>::iterator iterTemp= vecUsr.begin();iterTemp != vecUsr.end();iterTemp ++ ){CString strFormat;strFormat.Format( "編號:%s, 暱稱:%s\n",iterTemp->strUiD.c_str(),iterTemp->strNickName.c_str() );TRACE( strFormat.GetBuffer() );}TRACE( "\n***************************************************************\n" );for ( vector<Usr>::iterator iterUsr = vecUsr.begin();iterUsr != vecUsr.end();iterUsr ++ ){if ( iterUsr->strUiD == "10001" ){vector<Usr>::iterator iterEnd = vecUsr.erase( iterUsr );if ( iterEnd != vecUsr.end() ){CString strFormat;strFormat.Format( "編號:%s, 暱稱:%s\n",iterEnd->strUiD.c_str(),iterEnd->strNickName.c_str() );TRACE( strFormat.GetBuffer() );break;}}}TRACE( "\n***************************************************************\n" );for ( vector<Usr>::iterator iterTemp= vecUsr.begin();iterTemp != vecUsr.end();iterTemp ++ ){CString strFormat;strFormat.Format( "編號:%s, 暱稱:%s\n",iterTemp->strUiD.c_str(),iterTemp->strNickName.c_str() );TRACE( strFormat.GetBuffer() );}
程式的執行結果如下:
***************************************************************
編號:10001, 暱稱:袁孫良
編號:10002, 暱稱:張學友
編號:10003, 暱稱:劉德華
***************************************************************
編號:10001, 暱稱:張學友
***************************************************************
編號:10001, 暱稱:張學友
編號:10002, 暱稱:劉德華
結果令人詫異,iterEnd返回的本是10001後面的資料,(即編號:10002, 暱稱:張學友),結果返回id和暱稱對不上,更為甚者,ID居然是10001.
很多人看到這個程式很疑惑,為什麼代碼裡面會有這麼多的操作符的重載?
這個問題還要追溯到泛型演算法.泛型演算法很多操作都要重載比較操作符等一系列的操作符.如果我們的程式沒有這些操作符.程式無法編譯.
一般的C++教材裡面之所以不存在重載的問題,主要原因是他的類型一般是單一資料型別;如vector<int>,vector<string>等..
這些東西系統都內建了比較操作符.所以...
我們把賦值操作符去掉,發現整個程式正常運行.10001記錄
程式運行結果如下:
***************************************************************
編號:10001, 暱稱:袁孫良
編號:10002, 暱稱:張學友
編號:10003, 暱稱:劉德華
***************************************************************
編號:10002, 暱稱:張學友
***************************************************************
編號:10002, 暱稱:張學友
編號:10003, 暱稱:劉德華
看到erase函數裡面實際上調用了copy,而這個函數會和我們定義的賦值操作符有衝突.具體情況還不是很清楚.這個問題等我深入STL時在做結論.