STL序列式容器中删除元素的方法和陷阱 二

    技术2022-05-11  56

    STL序列式容器中删除元素的方法和陷阱 二 2.使用STL中通用算法或容器成员函数删除元素的方法 以上手工编写for循环代码删除容器中元素的方法也有一些问题,如果判断条件特别复杂,又有循环判断的话,循环中间又有异常处理的话,++itVect的位置就要小心放置了,稍不留意就要出错。所以手工编写代码删除容器中元素的方法不太安全,代码重复,也不够优雅,要注意的地方很多。 对于这种情况,可以考虑使用STL中通用算法remvoe()和remove_if()帮忙。而remvoe()和remove_if()这两个算法也有一个问题需要程序员特别小心。 在通用算法中的 remove (包括 remove_if 函数,并不真正从容器中删除元素,而是“应被删除的元素”被其后的“未被删除的元素”覆盖。返回值 ForwardIterator 指向经移除后的最后元素的下一位置。如 vector{0,1,2,3,3,4} ,执行 remove() ,希望移除所有值为 3 的元素,结果为 {0,1,2,4,3,4} ,返回值 ForwardIterator 指向第 5 个元素。即: 0        1        2        3         3       4 移除前 0        1        2        4         3       4 移除后   移除值为 3 的元素。移除后 3 被其后的 4 替代,最后两位元素为残余数据。   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;        } } 运行结果为: after deleted , size = 6 // 从这行可以看出,移除后容器的大小没变 i = 0 , 0 i = 1 , 1 i = 2 , 2 i = 3 , 4 //  从这行可以看出:“应被删除的元素” 3 被其后的“未被删除的元素” 4 覆盖 i = 4 , 3 i = 5 , 4        所以要彻底删除还应该把后面的残余数据删除掉,这可以通过调用容器的成员函数 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;        } } 运行结果为: after deleted , size = 4 // 从这行可以看出,删除后容器的大小变化了 i = 0 , 0 i = 1 , 1 i = 2 , 2 i = 3 , 4 从结果可以看出,所有值为 3 的元素确实被删除了。 对于 vector 容器存放其他比较复杂的对象,就可以用 remove_if() 加函数对象( 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;        //     由于两个函数对象要访问 CTest 类的 private 成员,所以设为友员。        friend class CStrFunc;        friend class CIntFunc; }; //     函数对象,根据 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;        } }; //     函数对象,根据 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 转化为 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();        } } 手工编写for循环代码删除STL序列式容器中元素的方法 ,使用 STL 中通用算法或容器成员函数删除元素的方法,两者之间的比较: 1.   前者代码重复。 2.   前者容易出错,不够清晰。 3.   效率: 0                  1           2       3                 2           5       6                 7 0                  1           3       2                 5           6       7 0                  1           3       5                 6           7   用第一种方法删除所有值为 2 的元素 从上图可以看出,每删除一个元素,后面的所有元素都到往前移动一位,导致一次内存大搬迁。   0                  1           2       3                 2           5       6                 7 0                  1           3       2                 5           6       6                 7 0                  1           3       5                 6           7     用第二种方法删除所有值为 2 的元素 从上面可以看出,删除时元素 2 被后面元素覆盖,不会到元素移位和内存大搬迁,残余数据留到末尾一次全部删除,也不会导致内存大搬迁,所以后者的方法要比前者在效率上好很多。  

    最新回复(0)