欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
STL序列式容器中刪除元素的方法和陷阱一 - CyberVisualink的專(zhuān)欄 - CS...

STL序列式容器中刪除元素的方法和陷阱一 收藏
在 STL (標準模板庫)中經(jīng)常會(huì )碰到要刪除容器中部分元素的情況,本人在編程中就經(jīng)常編寫(xiě)這方面的代碼,在編碼和測試過(guò)程中發(fā)現在 STL 中刪除容器有很多陷阱,網(wǎng)上也有不少網(wǎng)友提到如何在 STL 中安全刪除元素這些問(wèn)題。本文將討論編程過(guò)程中最經(jīng)常使用的兩個(gè)序列式容器 vector 、 list 中安全刪除元素的方法和應該注意的問(wèn)題,        其它如 queue 、 stack 等配接器容器( container adapter ),由于它們有專(zhuān)屬的操作行為,沒(méi)有迭代器( iterator ),不能采用本文介紹的刪除方法,至于 deque ,它與 vector 的刪除方法一樣。 STL 容器功能強大, but no siliver bullet ,如果你使用不當,也將讓你吃盡苦頭。

1 .手工編寫(xiě) for 循環(huán)代碼刪除 STL 序列式容器中元素的方法
例如,你能看出以下代碼有什么問(wèn)題?

例 1 :

#include <iostream>

#include <vector>

using namespace std;

void main( ) {

       vector<int> vectInt;

       int i;

       //     初始化 vector 容器

       for (i = 0; i < 5; i++ ) {

              vectInt.push_back( i );

       }

       //     以下代碼是要刪除所有值為 4 的元素

       vector<int>::iterator itVect = vectInt.begin();

       for ( ; itVect != vectInt.end();  ++itVect ) {

              if ( *itVect == 4 ) {

                     vectInt.erase( itVect );

              }

       }

       int iSize = vectInt.size();

      for (  i = 0 ; i < iSize; i++ )  {

                     cout << " i= " << i <<  ", " << vectInt[ i ] << endl;

       }

 

}

例 2 :

#include <iostream>

#include <vector>

using namespace std;

void main( ) {

       vector<int> vectInt;

       int i;

       //     初始化 vector 容器

       for ( i = 0; i < 5; i++ ) {

              vectInt.push_back( i );

              if ( 3 == i ) {

                     //       使 3 的元素有兩個(gè),并且相臨。這非常關(guān)鍵,否則將發(fā)現不了 bug 。

                     //   具體解釋見(jiàn)下。

                     vectInt.push_back( i );

              }

       }

       vector<int>::iterator itVect = vectInt.begin();

       vector<int>::iterator itVectEnd = vectInt.end(); //       防止 for 多重計算

       //     以下代碼是要刪除所有值為 3 的元素

       for ( ; itVect != itVectEnd; ++itVect ) {

              if ( *itVect == 3 ) {

                     itVect = vectInt.erase( itVect );

              }

       }

       int iSize = vectInt.size();

      for (  i = 0 ; i < iSize; i++ )  {

                     cout << " i= " << i <<  ", " << vectInt[ i ] << endl;

       }

例 3 :

#include <iostream>

#include <vector>

using namespace std;

void main( ) {

       vector<int> vectInt( 5 );

       int i;

       vectInt[ 0 ] = 0;

       vectInt[ 1 ] = 1;

       vectInt[ 2 ] = 2;

       vectInt[ 3 ] = 3;

       vectInt[ 4 ] = 4; //     替換為 vectInt[ 4 ] = 3; 試試

       vector<int>::iterator itVect = vectInt.begin();

       vector<int>::iterator itVectEnd = vectInt.end(); //       防止 for 多重計算

       //     以下代碼是要刪除所有值為 3 的元素

       for ( ; itVect != itVectEnd; ) {

              if ( *itVect == 3 ) {

                     itVect = vectInt.erase( itVect );

              }

              else {

                     ++itVect;

              }

       }

       int iSize = vectInt.size();

      for (  i = 0 ; i < iSize; i++ )  {

                     cout << " i= " << i <<  ", " << vectInt[ i ] << endl;

       }

}

 

分析:

這里最重要的是要理解 erase 成員函數,它刪除了 itVect 迭代器指向的元素,并且返回要被刪除的 itVect 之后的迭代器, 迭代器相當于一個(gè)智能指針,指向容器中的元素,現在刪除了這個(gè)元素,將導致內存重新分配,相應指向這個(gè)元素的迭代器之后的迭代器 就失效了,但 erase 成員函數返回要被刪除的 itVect 之后的迭代器 。

例 1 將導致程序未定義的錯誤,在 windows 中即是訪(fǎng)問(wèn)非法內存,程序當掉。因為 vectInt.erase( itVect ); 調用后 itVect 之后的迭代器已無(wú)效了,所以當執行 ++itVect 后, *itVect 訪(fǎng)問(wèn)了非法內存。例 1 也是初學(xué)者最容易犯的錯誤,這個(gè)錯誤也比較容易發(fā)現。

例 2 可能會(huì )導致不能把 vectInt 中所有為 3 的元素刪除掉。因為第一次刪除成功時(shí), itVect = vectInt.erase( itVect );itVect 為指向 3 之后的位置,之后再執行 ++itVect , itVect 就掉過(guò)了被刪除元素 3 之后的元素 3 ,導致只刪除了一個(gè)為 3 的元素,這個(gè) bug 比較隱蔽,因為如果不是兩個(gè)均為 3 的元素相臨,就將很難捕捉到這個(gè) bug ,程序有可能在一段時(shí)間運行良好,但如碰到容器中兩值相同的元素相臨,則程序就要出問(wèn)題。

例 3 ,對于本例你可能要說(shuō)程序沒(méi)有任何問(wèn)題,解決了上面的兩個(gè) bug ,程序也運行正常。但且慢,你把 “ vectInt[ 4 ] = 4; ” 這一行改為 “ vectInt[ 4 ] = 3; ”試試,一運行,程序當掉,訪(fǎng)問(wèn)非法內存!你疑惑不解:從程序看不出 bug ,而且我還把 vectInt.end() 放在外面計算以防止 for 多重計算,提高效率。哈哈,問(wèn)題就出在最后一句話(huà)!算法大師 Donald Knuth 有一句名言:不成熟的優(yōu)化是一切惡果的根源( Permature optimization is the root of all evil )。由于在 for 循環(huán)中要刪除元素,則 vectInt.end() 是會(huì )變化的,所以不能在 for 循環(huán)外計算,而是每刪除一次都要重新計算,所以應放在 for 循環(huán)內。那你要問(wèn),為什么把 “ vectInt[ 4 ] = 4; ” 這一行改為 “ vectInt[ 4 ] = 3; ”程序就會(huì )當掉,而不改程序就很正常呢?這就跟 vector 的實(shí)現機制有關(guān)了。下面以圖例詳細解釋。

vectInt 的初始狀態(tài)為:

 

                                                                             | end

0        1        2        3         4     

                                     

刪除 3 后,

 

                                                                 | 新的 end  | 原來(lái)的 end

0         1        2        4         4     

 

 

 

注意上面“新的 end ”指向的內存并沒(méi)有被清除,為了效率, vector 會(huì )申請超過(guò)需要的內存保存數據,刪除數據時(shí)也不會(huì )把多余的內存刪除。

然后 itVect 再執行 ++itVect ,因為此時(shí) *itVect 等于 4 ,所以繼續循環(huán), 這時(shí) itVect 等于“新的 end ”但不等于“原來(lái)的 end ”(它即為 itVectEnd ),所以繼續,因為 *itVect 訪(fǎng)問(wèn)的是只讀內存得到的值為 4 ,不等于 3 ,故不刪除,然后執行 ++itVect 此時(shí) itVect 等于 itVectEnd 退出循環(huán)。從上面過(guò)程可以看出,程序多循環(huán)了一次(刪除幾次,就要多循環(huán)幾次),但程序正常運行。

如果把 “ vectInt [ 4 ] = 4; ” 這一行改為 “ vectInt [ 4 ] = 3; ”過(guò)程如下:

 

 

                                                                        | end

0        1        2        3         3     

 

刪除 3 后,

 

                                                                 | 新的 end       | 原來(lái)的 end

0        1        2        3         3      

 

 

刪除第 2 個(gè) 3 后,

 

                                                 | 新的 end            | 原來(lái)的 end

0        1        2        3         3     

 

這時(shí) itVect 等于“新的 end ”但不等于“原來(lái)的 end ”(它即為 itVectEnd ),所以繼續,因為 *itVect 訪(fǎng)問(wèn)的是只讀內存得到的值為 3 ,等于 3 ,所以執行刪除,但因為 *itVect 訪(fǎng)問(wèn)的是只讀內存不能刪除,所以程序當掉。

綜上,我們知道當要刪除的值在容器末尾時(shí),會(huì )導致程序刪除非法內存,程序當掉;即使程序正常運行,也是 for 循環(huán)多執行了等于刪除個(gè)數的循環(huán)。所以把 vectInt.end() 放在 for 循環(huán)外面執行,完全是錯誤的。對于 list 容器, list.end() 在刪除過(guò)程中是不會(huì )變的,可以把它放在 for 循環(huán)外面計算,但由于 list.end() 是個(gè)常量,把 list.end() 放在 for 循環(huán)中計算編譯器應該可以?xún)?yōu)化它。從安全考慮,除非你能保證 for 循環(huán)中不會(huì )改變容器的大小,否則都應該對容器的值在 for 循環(huán)中計算,對于 vectInt.size() 這樣的計算,也應該在 for 循環(huán)中計算,不要因為微小的優(yōu)化而導致程序出錯。

 

正確的方法:

例 4 :

#include <iostream>

#include <vector>

using namespace std;

void main( ) {

       vector<int> vectInt;

       int i;

       for (  i = 0; i < 5; i++ ) {

              vectInt.push_back( i );

              if ( 3 == i ) {

                     //       使 3 的元素有兩個(gè),并且相臨。

                     vectInt.push_back( i );

              }

       }

       vector<int>::iterator itVect = vectInt.begin();

       //     以下代碼是要刪除所有值為 3 的元素

       for ( ; itVect != vectInt.end();  ) {  // 刪除 ++itVect{

              if ( *itVect == 3 ) {

                     itVect = vectInt.erase( itVect );

              }

              else {

                     ++itVect;

              }

       }

       //     把 vectInt.size() 放在 for 循環(huán)中

      for (  i = 0 ; i < vectInt.size(); i++ )  {

                     cout << " i= " << i <<  ", " << vectInt[ i ] << endl;

       }

運行結果為:

i= 0, 0

i= 1, 1

i= 2, 2

i= 3, 4

從結果顯示值為 3 的元素確實(shí)被刪除了。


本文來(lái)自CSDN博客,轉載請標明出處:http://blog.csdn.net/OExpress/archive/2006/06/15/799572.aspx

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
什么是STL
STL之vector的使用
STL模板總結
STL學(xué)習總結
stl容器學(xué)習總結
C++基礎相關(guān)STL::List 用法簡(jiǎn)單介紹
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久