• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            posts - 297,  comments - 15,  trackbacks - 0

                在STL(標(biāo)準(zhǔn)模板庫(kù))中經(jīng)常會(huì)碰到要?jiǎng)h除容器中部分元素的情況,本人在編程中就經(jīng)常編寫(xiě)這方面的代碼,在編碼和測(cè)試過(guò)程中發(fā)現(xiàn)在STL中刪除容器有很多陷阱,網(wǎng)上也有不少網(wǎng)友提到如何在STL中安全刪除元素這些問(wèn)題。本文將討論編程過(guò)程中最經(jīng)常使用的兩個(gè)序列式容器vector、list中安全刪除元素的方法和應(yīng)該注意的問(wèn)題,       其它如queue、stack等配接器容器(container adapter),由于它們有專屬的操作行為,沒(méi)有迭代器(iterator),不能采用本文介紹的刪除方法,至于deque,它與vector的刪除方法一樣。STL容器功能強(qiáng)大,but no siliver bullet,如果你使用不當(dāng),也將讓你吃盡苦頭。
                這里最重要的是要理解erase成員函數(shù),它刪除了itVect迭代器指向的元素,并且返回要被刪除的itVect之后的迭代器,迭代器相當(dāng)于一個(gè)智能指 針,指向容器中的元素,現(xiàn)在刪除了這個(gè)元素,將導(dǎo)致內(nèi)存重新分配,相應(yīng)指向這個(gè)元素的迭代器之后的迭代器就失效了,但erase成員函數(shù)返回要被刪除的 itVect之后的迭代器。

            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 );
                   }
                   //     以下代碼是要?jiǎng)h除所有值為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;
                   }
            }

                例1將導(dǎo)致程序未定義的錯(cuò)誤,在windows中即是訪問(wèn)非法內(nèi)存,程序當(dāng)?shù)簟R驗(yàn)関ectInt.erase( itVect );調(diào)用后itVect之后的迭代器已無(wú)效了,所以當(dāng)執(zhí)行++itVect后,*itVect訪問(wèn)了非法內(nèi)存。例1也是初學(xué)者最容易犯的錯(cuò)誤,這個(gè)錯(cuò)誤也 比較容易發(fā)現(xiàn)。

            例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ā)現(xiàn)不了bug。
                                 //   具體解釋見(jiàn)下。
                                 vectInt.push_back( i );
                           }
                   }
                   vector<int>::iterator itVect = vectInt.begin();
                   vector<int>::iterator itVectEnd = vectInt.end(); //       防止for多重計(jì)算
                   //     以下代碼是要?jiǎng)h除所有值為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;
                   }

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


            例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多重計(jì)算
                   //     以下代碼是要?jiǎng)h除所有值為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;
                   }
            }
            例3,對(duì)于本例你可能要說(shuō)程序沒(méi)有任何問(wèn)題,解決了上面的兩個(gè)bug,程序也運(yùn)行正常。但且慢,你把 “vectInt[ 4 ] = 4;” 這一行改為 “vectInt[ 4 ] = 3;”試試,一運(yùn)行,程序當(dāng)?shù)簦L問(wèn)非法內(nèi)存!你疑惑不解:從程序看不出bug,而且我還把vectInt.end()放在外面計(jì)算以防止for多重計(jì)算,提高效率。哈哈,問(wèn)題就出在最后一句話!算法大師Donald Knuth有一句名言:不成熟的優(yōu)化是一切惡果的根源( Permature optimization is the root of all evil )。由于在for循環(huán)中要?jiǎng)h除元素,則vectInt.end()是會(huì)變化的,所以不能在for循環(huán)外計(jì)算,而是每刪除一次都要重新計(jì)算,所以應(yīng)放在 for循環(huán)內(nèi)。那你要問(wèn),為什么把 “vectInt[ 4 ] = 4;” 這一行改為 “vectInt[ 4 ] = 3;”程序就會(huì)當(dāng)?shù)簦桓某绦蚓秃苷D兀窟@就跟vector的實(shí)現(xiàn)機(jī)制有關(guān)了。下面以圖例詳細(xì)解釋。
            vectInt的初始狀態(tài)為:

                                              | end
            0   1   2   3   4                                  

            刪除3后,

                                   |新的end   | 原來(lái)的end
            0   1   2   4   4    


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

            然后itVect再執(zhí)行++itVect,因?yàn)榇藭r(shí)*itVect等于4,所以繼續(xù)循環(huán), 這時(shí)itVect 等于“新的end”但不等于“原來(lái)的end”(它即為itVectEnd),所以繼續(xù),因?yàn)?*itVect訪問(wèn)的是只讀內(nèi)存得到的值為4,不等于3,故不刪除,然后執(zhí)行++itVect此時(shí)itVect等于itVectEnd退出循環(huán)。從上面過(guò)程可以看出,程序多循環(huán)了一次(刪除幾次,就要多循環(huán)幾次),但程序正常運(yù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),所以繼續(xù),因?yàn)?*itVect訪問(wèn)的是只讀內(nèi)存得到的值為3,等于3,所以執(zhí)行刪除,但因?yàn)?itVect訪問(wèn)的是只讀內(nèi)存不能刪除,所以程序當(dāng)?shù)簟?br>
            綜上,我們知道當(dāng)要?jiǎng)h除的值在容器末尾時(shí),會(huì)導(dǎo)致程序刪除非法內(nèi)存,程序當(dāng)?shù)簦患词钩绦蛘_\(yùn)行,也是for循環(huán)多執(zhí)行了等于刪除個(gè)數(shù)的循環(huán)。所以把 vectInt.end()放在for循環(huán)外面執(zhí)行,完全是錯(cuò)誤的。對(duì)于list容器,list.end()在刪除過(guò)程中是不會(huì)變的,可以把它放在for 循環(huán)外面計(jì)算,但由于list.end()是個(gè)常量,把list.end()放在for循環(huán)中計(jì)算編譯器應(yīng)該可以優(yōu)化它。從安全考慮,除非你能保證for 循環(huán)中不會(huì)改變?nèi)萜鞯拇笮。駝t都應(yīng)該對(duì)容器的值在for循環(huán)中計(jì)算,對(duì)于 vectInt.size()這樣的計(jì)算,也應(yīng)該在for循環(huán)中計(jì)算,不要因?yàn)槲⑿〉膬?yōu)化而導(dǎo)致程序出錯(cuò)。


            正確的方法:
            例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();

                   //     以下代碼是要?jiǎng)h除所有值為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;
                   }

            運(yùn)行結(jié)果為:
            i= 0, 0
            i= 1, 1
            i= 2, 2
            i= 3, 4

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

            2.使用STL中通用算法或容器成員函數(shù)刪除元素的方法
            以上手工編寫(xiě)for循環(huán)代碼刪除容器中元素的方法也有一些問(wèn)題,如果判斷條件特別復(fù)雜,又有循環(huán)判斷的話,循環(huán)中間又有異常處理的話,++itVect的位置就要小心放置了,稍不留意就要出錯(cuò)。所以手工編寫(xiě)代碼刪除容器中元素的方法不太安全,代碼重復(fù),也不夠優(yōu)雅,要注意的地方很多。

            對(duì)于這種情況,可以考慮使用STL中通用算法remvoe()和remove_if()幫忙。而remvoe()和remove_if()這兩個(gè)算法也有一個(gè)問(wèn)題需要程序員特別小心。在通用算法中的 remove(包括remove_if)函數(shù),并不真正從容器中刪除元素,而是“應(yīng)被刪除的元素”被其后的“未被刪除的元素”覆蓋。返回值ForwardIterator指向經(jīng)移除后的最后元素的下一位置。如vector{0,1,2,3,3,4},執(zhí)行remove(),希望移除所有值為3的元素,結(jié)果為{0,1,2,4,3,4},返回值 ForwardIterator指向第5個(gè)元素。即:

            0         1         2         3         3       4   移除前

            0         1         2         4         3       4   移除后


            移除值為3的元素。移除后3被其后的4替代,最后兩位元素為殘余數(shù)據(jù)。

            例 5:

            void main() {
                   vector<int> vectInt;
                   int i;
                   for (i = 0; i < 5; i++ ) {
                           vectInt.push_back( i );
                           if ( 3 == i ) {
                                 vectInt.push_back( i );
                           }
                   }
                   remove( vectInt.begin(), vectInt.end(), 3 );
                   cout << " after deleted , size = " << vectInt.size() << endl;
                   for ( i = 0; i < vectInt.size();; i++ ) {
                           cout << "i = " << i << " , " << vectInt[i] << endl;
                   }
            }
            運(yùn)行結(jié)果為:
            after deleted , size = 6 // 從這行可以看出,移除后容器的大小沒(méi)變
            i = 0 , 0
            i = 1 , 1
            i = 2 , 2
            i = 3 , 4 //   從這行可以看出:“應(yīng)被刪除的元素”3 被其后的“未被刪除的元素”4覆蓋
            i = 4 , 3
            i = 5 , 4    

            所以要徹底刪除還應(yīng)該把后面的殘余數(shù)據(jù)刪除掉,這可以通過(guò)調(diào)用容器的成員函數(shù)erase()做到。

            例 6:
            void main() {
                   vector<int> vectInt;
                   int i;
                   for (i = 0; i < 5; i++ ) {
                           vectInt.push_back( i );
                           if ( 3 == i ) {
                                 vectInt.push_back( i );
                           }
                   }
                   vectInt.erase( remove( vectInt.begin(), vectInt.end(), 3 ), vectInt.end() );
                   cout << " after deleted , size = " << vectInt.size() << endl;
                   for ( i = 0; i < vectInt.size();; i++ ) {
                           cout << "i = " << i << " , " << vectInt[i] << endl;
                   }
            }

            運(yùn)行結(jié)果為:
            after deleted , size = 4 // 從這行可以看出,刪除后容器的大小變化了
            i = 0 , 0
            i = 1 , 1
            i = 2 , 2
            i = 3 , 4
            從結(jié)果可以看出,所有值為3的元素確實(shí)被刪除了。
            對(duì)于vector容器存放其他比較復(fù)雜的對(duì)象,就可以用remove_if()加函數(shù)對(duì)象(Function Object)的方法。
            如:
            例7:
            #include <iostream>
            #include <sstream>
            #include <string>
            #include <vector>
            #include <algorithm>
            #include <list>
            using namespace std;
            class CTest {
            public:
                   CTest( const string& str, int iPrice ) : m_strName( str ), m_iPrice( iPrice ) { }
                   void vPrint() { cout << "name=" << m_strName << " price = " << m_iPrice << endl;
                   }
            private:
                   string m_strName;
                   int   m_iPrice;
                   //     由于兩個(gè)函數(shù)對(duì)象要訪問(wèn)CTest類的private成員,所以設(shè)為友員。
                   friend class CStrFunc;
                   friend class CIntFunc;
            };

            //     函數(shù)對(duì)象,根據(jù)string比較
            class CStrFunc {
                   string m_str;
            public:
                   CStrFunc( const string& str ) : m_str( str ) {
                   }
                   bool operator() ( const CTest& left ) {
                           return ( m_str == left.m_strName ) ? true : false;
                   }
            };

            //     函數(shù)對(duì)象,根據(jù)int比較
            class CIntFunc {
                   int m_iPrice;
            public:
                   CIntFunc( int iPrice ) : m_iPrice( iPrice ) {
                   }
                   bool operator() ( const CTest& left ) {
                           return ( m_iPrice == left.m_iPrice ) ? true : false;
                   }
            };

            void main( ) {

                   vector< CTest > vectTest;
                   int i;
                   for (   i = 0; i < 5 ; i++ ) {
                           stringstream stream; //       流格式化符,把int轉(zhuǎn)化為string
                           stream << i;
                           string str = stream.str();
                           CTest clTest( str, i );
                           vectTest.push_back( clTest );
                   }
                   for (   i = 0 ; i < vectTest.size(); i++ )   {
                           vectTest[ i ].vPrint();
                   }
                   //     刪除所有m_strName = "3"的元素
                   vectTest.erase( remove_if( vectTest.begin(), vectTest.end(), CStrFunc( "3" ) ),
                           vectTest.end() );
                   cout << "delete 3 after : " << endl;
                   for (   i = 0 ; i < vectTest.size(); i++ )   {
                           vectTest[ i ].vPrint();
                   }
                   //     刪除所有m_iPrice = 2的元素
                   vectTest.erase( remove_if( vectTest.begin(), vectTest.end(), CIntFunc( 2 ) ),
                           vectTest.end() );
                   cout << "delete 2 after : " << endl;
                   for (   i = 0 ; i < vectTest.size(); i++ )   {
                           vectTest[ i ].vPrint();
                   }
            }
            手工編寫(xiě)for循環(huán)代碼刪除STL序列式容器中元素的方法,使用STL中通用算法或容器成員函數(shù)刪除元素的方法,兩者之間的比較:
            1.   前者代碼重復(fù)。
            2.   前者容易出錯(cuò),不夠清晰。
            3.   效率:
            0                   1           2       3                 2           5       6                 7
            0                   1           3       2                 5           6       7
            0                   1           3       5                 6           7
            用第一種方法刪除所有值為2的元素
            從上圖可以看出,每刪除一個(gè)元素,后面的所有元素都到往前移動(dòng)一位,導(dǎo)致一次內(nèi)存大搬遷。

            0                   1           2       3                 2           5       6                 7
            0                   1           3       2                 5           6       6                 7
            0                   1           3       5                 6           7

            用第二種方法刪除所有值為2的元素
            從上面可以看出,刪除時(shí)元素2被后面元素覆蓋,不會(huì)到元素移位和內(nèi)存大搬遷,殘余數(shù)據(jù)留到末尾一次全部刪除,也不會(huì)導(dǎo)致內(nèi)存大搬遷,所以后者的方法要比前者在效率上好很多。 

            3.list容器中刪除元素的方法
            對(duì)于list容器,由于list本身有remove和remove_if的成員函數(shù),所以最好優(yōu)先考慮list自己的算法,對(duì)于remove函數(shù),比較簡(jiǎn)單,不再討論,對(duì)于remove_if函數(shù),本人發(fā)現(xiàn)在vc6.0中有重大問(wèn)題。我試了多種函數(shù)對(duì)象,總是編譯不過(guò),通過(guò)查看源代碼,才發(fā)現(xiàn)VC6.0中對(duì)remove_if()函數(shù)作了簡(jiǎn)化,只提供了一種比較函數(shù),它只能刪除不等于某值的元素,VC6.0種remove_if()函數(shù)的源碼如下:
            typedef binder2nd<not_equal_to<_Ty> > _Pr1;
                   void remove_if(_Pr1 _Pr)
                           {iterator _L = end();
                           for (iterator _F = begin(); _F != _L; )
                                 if (_Pr(*_F))
                                         erase(_F++);
                                 else
                                         ++_F; }
            從源碼中可以看出,remove_if中_Pr1函數(shù)對(duì)象被固定為binder2nd<not_equal_to<_Ty> >一種格式。而在VC7.0中已經(jīng)修改了這個(gè)bug,源碼如下:
            template<class _Pr1>
                           void remove_if(_Pr1 _Pred)
                           {     // erase each element satisfying _Pr1
                           iterator _Last = end();
                           for (iterator _First = begin(); _First != _Last; )
                                 if (_Pred(*_First))
                                         erase(_First++);
                                 else
                                         ++_First;
                           }
            在VC7.0中remove_if()是成員模板函數(shù),可以用任何判斷條件的函數(shù)對(duì)象。
            例如:
            例 8:
            #include <iostream>
            #include <string>
            #include <list>
            #include <algorithm>
            using namespace std;
            class CTest{
            public:
                   CTest( int i ) : m_iPrice ( i ) {     }
                   int operator == ( const CTest& right ) const{
                           return ( m_iPrice == right.m_iPrice ) ? 1 : 0;
                   }
                   int operator != ( const CTest& right ) const{
                           return ( m_iPrice != right.m_iPrice ) ? 1 : 0;
                   }
                   int operator < ( const CTest& right ) const {
                           return ( m_iPrice < right.m_iPrice ) ? 1 : 0;
                   }
            private:
                   int m_iPrice;
                   friend class CTestFunc;
            };
            class CTestFunc {             //       函數(shù)對(duì)象
            public:
                   int m_value;
                   CTestFunc( int i ) : m_value( i ) {}
                   bool operator () ( const CTest& clFirst ) {
                           return ( clFirst.m_iPrice == m_value ) ? true : false;     }
            };
            void main() {
                   list< CTest > listTest;
                   for ( int i = 0; i < 5; i++ ) {
                           CTest clTest( i );
                           listTest.push_back( clTest );
                   }
                   cout << "remove before : " << listTest.size() << endl;
            //     刪除所有為2的元素
                   listTest.remove_if( CTestFunc( 2 )   ); //       這條語(yǔ)句在vc6.0中不能編譯通過(guò),VC7.0中可以
                   cout << "remove after : 2, size =   " << listTest.size() << endl;

                   //     刪除所以不等于2的元素,VC6.0中只能以這種方式調(diào)用remove_if()函數(shù)
                   listTest.remove_if(   bind2nd( not_equal_to<CTest>(), 2 )     );
                   cout << "remove after not equal to 2, size =   " << listTest.size() << endl;

                   //     因?yàn)镃Test類提供了==、< 成員函數(shù),所以也可以用remove函數(shù)
                   listTest.remove( 2 ); //       刪除所有為2的元素
                   cout << "remove after : 2, size =   " << listTest.size() << endl;
            }

            不知道在VC6.0中能否突破只能函數(shù)對(duì)象被固定為binder2nd<not_equal_to<_Ty> >一種格式的限制?歡迎諸位大蝦不吝賜教。不過(guò)采用通用算法remove_if只是多了幾次對(duì)象的賦值的負(fù)擔(dān),如果對(duì)象不是太大,用通用算法的性能也是可以接受的。

            另外,這些天使用了VC7.0后,感覺(jué)非常棒,不僅幾乎符合Standard C++規(guī)范,錯(cuò)誤提示也更清晰,而編譯速度和編譯后的文件大小大大減小,如我原來(lái)的一個(gè)大量使用了模板的程序,用VC6.0編譯后Release版的可執(zhí)行文件大小為1.2M,用VC7.0編譯后只有420K,我想可能VC7.0在代碼優(yōu)化和模板代碼的膨脹等方面有了極大的改善;在STL的實(shí)現(xiàn)上也有了極大的改進(jìn),把原來(lái)的一些效率不好的地方都改進(jìn)了,處理策略基本與SGI STL一致。

            4.STL容器中元素為指針情況下的刪除方法
            對(duì)于容器中的元素為指針的刪除方法。如果容器中的元素為指針則不能用上面介紹的用通過(guò)算法或成員函數(shù)的方法刪除元素,因?yàn)槟菢幼鰰?huì)導(dǎo)致內(nèi)存泄露,容器中的元素為指針指向的內(nèi)存沒(méi)有釋放,在這種情況下有以下方法解決:

            1.   盡可能不用指針作為容器的元素。

            2.   如果是因?yàn)橐獪p少對(duì)象拷貝和賦值方面的負(fù)擔(dān),而要在容器中存放指針的話,可以考慮用boost庫(kù)中的智能指針shared_ptr包裝指針,達(dá)到容器中引用的語(yǔ)意。

            3.   如果你不希望因?yàn)槭褂胋oost::shared_ptr增加引用計(jì)數(shù)的負(fù)擔(dān),認(rèn)為引入智能指針不好理解,那么你用指針作為容器的元素要千萬(wàn)小心,這時(shí)你要自己管理內(nèi)存。

            例如:    

            例 9:用boost庫(kù)中的智能指針shared_ptr包裝指針的例子:
            #include <iostream>
            #include <sstream>
            #include <string>
            #include <vector>
            #include <algorithm>
            #include <list>
            #include <boost\smart_ptr.hpp> // 要包含BOOST類庫(kù)中智能指針的頭文件
            using namespace std;
            class CTest {
            public:
                   CTest( const string& str, int iPrice ) : m_strName( str ), m_iPrice( iPrice ) { }
                   void vPrint() { cout << "name=" << m_strName << " price = " << m_iPrice << endl;
                   }

            private:
                   string m_strName;
                   int   m_iPrice;
                   friend class CStrFunc;
                   friend class CIntFunc;
            };

            //     函數(shù)對(duì)象,根據(jù)string比較
            class CStrFunc {
                   string m_str;

            public:
                   CStrFunc( const string& str ) : m_str( str ) {
                   }
                   //     此處要改為boost::shared_ptr<CTest>&,因?yàn)関ector容器中的元素為
            //       boost::shared_ptr<CTest>
                   bool operator() ( const boost::shared_ptr<CTest>& left ) {
                           return ( m_str == (*left).m_strName ) ? true : false;
                   }

            };

            //     函數(shù)對(duì)象,根據(jù)int比較
            class CIntFunc {
                   int m_iPrice;
            public:
                   CIntFunc( int iPrice ) : m_iPrice( iPrice ) {
                   }
            //     此處要改為boost::shared_ptr<CTest>&,因?yàn)関ector容器中的元素為
            //       boost::shared_ptr<CTest>
                   bool operator() ( const boost::shared_ptr<CTest>& left ) {
                           return ( m_iPrice == (*left).m_iPrice ) ? true : false;
                   }
            };
            void main( ) {

                   vector< boost::shared_ptr<CTest>   > vectTest;
                   int i;
                   for (   i = 0; i < 5 ; i++ ) {
                           stringstream stream;
                           stream << i;
                           string str = stream.str();
                           boost::shared_ptr<CTest>   ptrShare( new CTest( str, i ) );
                           vectTest.push_back( ptrShare );
                   }
                   for (   i = 0 ; i < vectTest.size(); i++ )   {
                           ( *vectTest[ i ] ).vPrint();
                   }
                   //     刪除所有m_strName = "3"的元素
                   vectTest.erase( remove_if( vectTest.begin(), vectTest.end(), CStrFunc( "3" ) ),
                           vectTest.end() );
                   cout << "delete 3 after : " << endl;
                   for (   i = 0 ; i < vectTest.size(); i++ )   {
                           ( *vectTest[ i ] ).vPrint();
                   }
                   //     刪除所有m_iPrice = 2的元素
                   vectTest.erase( remove_if( vectTest.begin(), vectTest.end(), CIntFunc( 2 ) ),
                           vectTest.end() );
                   cout << "delete 2 after : " << endl;
                   for (   i = 0 ; i < vectTest.size(); i++ )   {
                           ( *vectTest[ i ] ).vPrint();
                   }
            }

            以上代碼不會(huì)導(dǎo)致內(nèi)存泄露。

            例 10:自己編程刪除容器中元素為指針的例子:

            #include <iostream>
            #include <sstream>
            #include <string>
            #include <vector>
            #include <algorithm>
            using namespace std;
            class CTest {
            public:
                   CTest( const string& str, int iPrice ) : m_strName( str ), m_iPrice( iPrice ) { }
                   void vPrint() { cout << "name=" << m_strName << " price = " << m_iPrice << endl;
                   }
            private:
                   string m_strName;
                   int   m_iPrice;
                   //     聲明友員函數(shù),因?yàn)関DeleteVector函數(shù)要訪問(wèn)CTest的private成員變量
                   friend void vDeleteVector( vector< CTest*   >& vectTest, const string& str );
                   friend void vDeleteVector( vector< CTest*   >& vectTest, int iPrice );
            };
            //     根據(jù)CTest類中m_strName比較
            void vDeleteVector( vector< CTest*   >& vectTest, const string& str ) {
                   vector< CTest* >::iterator itVect = vectTest.begin();
                   for ( ; itVect != vectTest.end();; ) {
                           if ( (*itVect)->m_strName == str ) {
                                 //       刪除vector容器中指針元素指向的內(nèi)容,防止內(nèi)存泄露
                                 delete *itVect;
                                 itVect = vectTest.erase( itVect );
                           }
                           else {
                                 ++itVect;
                           }
                   }
            }
            //     根據(jù)CTest類中m_iPrice比較
            void vDeleteVector( vector< CTest*   >& vectTest, int iPrice ) {
                   vector< CTest* >::iterator itVect = vectTest.begin();
                   for ( ; itVect != vectTest.end(); ) {
                           if ( (*itVect)->m_iPrice == iPrice ) {
                                 //       刪除vector容器中指針元素指向的內(nèi)容,防止內(nèi)存泄露
                                 delete *itVect;
                                 itVect = vectTest.erase( itVect );
                           }
                           else {
                                 ++itVect;
                           }
                   }
            }

            void main( ) {
                   vector< CTest*   > vectTest;
                   int i;
                   for (   i = 0; i < 5 ; i++ ) {
                           stringstream stream;
                           stream << i;
                           string str = stream.str();
                           CTest* pclTest =   new CTest( str, i ) ;
                           vectTest.push_back( pclTest );
                   }
                   for (   i = 0 ; i < vectTest.size(); i++ )   {
                           vectTest[ i ]->vPrint();
                   }
                   //     刪除所有m_strName = "5"的元素
                   vDeleteVector( vectTest, "3" );
                   cout << "delete 3 after : " << endl;
                   for (   i = 0 ; i < vectTest.size(); i++ )   {
                           vectTest[ i ]->vPrint();
                   }
                   //     刪除所有m_iPrice = 2的元素
                   vDeleteVector( vectTest, 2 );
                   cout << "delete 2 after : " << endl;
                   for (   i = 0 ; i < vectTest.size(); i++ )   {
                           vectTest[ i ]->vPrint();
                   }
            }
            原則:
            1.   盡可能用通用算法。相信STL的算法要比自己的實(shí)現(xiàn)高效、優(yōu)雅、安全。
            2.   優(yōu)先用容器自身的成員函數(shù)。 見(jiàn)《Effective STL》中 Item 44: Prefer member functions to algorithms with the same names
            3.   盡可能熟悉函數(shù)對(duì)象。
            4.   多看STL的源碼,了解其實(shí)作。
            5.   不成熟的優(yōu)化是一切惡果的根源。編寫(xiě)代碼,安全第一。
            綜上,在STL中刪除容器中部分元素時(shí)要特別小心,不過(guò)通過(guò)使用通用算法或容器本身的刪除函數(shù),能大大減小重復(fù)代碼和程序出錯(cuò)的機(jī)會(huì),能夠使代碼得到優(yōu)化,生成高效的代碼。

            posted on 2008-07-09 22:32 chatler 閱讀(2182) 評(píng)論(0)  編輯 收藏 引用 所屬分類: GP_STL
            <2008年7月>
            293012345
            6789101112
            13141516171819
            20212223242526
            272829303112
            3456789

            常用鏈接

            留言簿(10)

            隨筆分類(307)

            隨筆檔案(297)

            algorithm

            Books_Free_Online

            C++

            database

            Linux

            Linux shell

            linux socket

            misce

            • cloudward
            • 感覺(jué)這個(gè)博客還是不錯(cuò),雖然做的東西和我不大相關(guān),覺(jué)得看看還是有好處的

            network

            OSS

            • Google Android
            • Android is a software stack for mobile devices that includes an operating system, middleware and key applications. This early look at the Android SDK provides the tools and APIs necessary to begin developing applications on the Android platform using the Java programming language.
            • os161 file list

            overall

            搜索

            •  

            最新評(píng)論

            閱讀排行榜

            評(píng)論排行榜

            久久er99热精品一区二区| 91秦先生久久久久久久| 色婷婷综合久久久久中文一区二区| 色综合久久久久综合体桃花网| 97久久超碰成人精品网站| 久久精品国产第一区二区| 漂亮人妻被黑人久久精品| 久久久久18| 久久精品一区二区三区不卡| 久久精品国产精品亚洲精品| 国产成人精品久久一区二区三区av | 99久久精品国产麻豆| 人人狠狠综合久久亚洲| 久久99久久99小草精品免视看| 伊人久久大香线蕉综合网站| 精品久久久久久| 久久久噜噜噜久久中文福利| 亚洲人AV永久一区二区三区久久 | 久久99国产一区二区三区| 久久久久久国产精品无码超碰| 久久久精品久久久久影院| 精品人妻伦九区久久AAA片69 | 热99RE久久精品这里都是精品免费 | 97久久久久人妻精品专区| 欧美日韩精品久久久久| 久久久国产精华液| 久久人人爽人人爽AV片| 国产精品久久久天天影视香蕉| 69久久夜色精品国产69 | 久久精品国产WWW456C0M| 91麻豆精品国产91久久久久久| 国产精品久久久久影视不卡| 97久久超碰国产精品旧版| 99久久国产综合精品麻豆| 久久综合综合久久97色| 久久综合狠狠色综合伊人| 日本三级久久网| 亚洲国产高清精品线久久| 久久无码国产专区精品| 香蕉久久夜色精品升级完成| 久久国产精品77777|