3.list容器中删除元素的方法<o:p></o:p>
对于list容器,由于list本身有remove和remove_if的成员函数,所以最好优先考虑list自己的算法,对于remove函数,比较简单,不再讨论,对于remove_if函数,本人发现在vc6.0中有重大问题。我试了多种函数对象,总是编译不过,通过查看源代码,才发现VC6.0中对remove_if()函数作了简化,只提供了一种比较函数,它只能删除不等于某值的元素,VC6.0种remove_if()函数的源码如下:
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函数对象被固定为binder2nd<not_equal_to<_Ty> >一种格式。而在VC7.0中已经修改了这个bug,源码如下:<o:p></o:p>
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()是成员模板函数,可以用任何判断条件的函数对象。<o:p></o:p>
例如:<o:p></o:p>
例 8:<o:p></o:p>
#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 { // 函数对象
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 ) ); // 这条语句在vc6.0中不能编译通过,VC7.0中可以
cout << "remove after : 2, size = " << listTest.size() << endl;
<o:p></o:p>
// 删除所以不等于2的元素,VC6.0中只能以这种方式调用remove_if()函数
listTest.remove_if( bind2nd( not_equal_to<CTest>(), 2 ) );
cout << "remove after not equal to 2, size = " << listTest.size() << endl;
<o:p></o:p>
// 因为CTest类提供了==、< 成员函数,所以也可以用remove函数
listTest.remove( 2 ); // 删除所有为2的元素
cout << "remove after : 2, size = " << listTest.size() << endl;
}
不知道在VC6.0中能否突破只能函数对象被固定为binder2nd<not_equal_to<_Ty> >一种格式的限制?欢迎诸位不吝赐教。不过采用通用算法remove_if只是多了几次对象的赋值的负担,如果对象不是太大,用通用算法的性能也是可以接受的。<o:p></o:p>
另外,这些天使用了VC7.0后,感觉非常棒,不仅几乎符合Standard C++规范,错误提示也更清晰,而编译速度和编译后的文件大小大大减小,如我原来的一个大量使用了模板的程序,用VC6.0编译后Release版的可执行文件大小为1.2M,用VC7.0编译后只有420K,我想可能VC7.0在代码优化和模板代码的膨胀等方面有了极大的改善;在STL的实现上也有了极大的改进,把原来的一些效率不好的地方都改进了,处理策略基本与SGI STL一致。<o:p></o:p>
4.STL容器中元素为指针情况下的删除方法<o:p></o:p>
对于容器中的元素为指针的删除方法。如果容器中的元素为指针则不能用上面介绍的用通过算法或成员函数的方法删除元素,因为那样做会导致内存泄露,容器中的元素为指针指向的内存没有释放,在这种情况下有以下方法解决:<o:p></o:p>
1. 尽可能不用指针作为容器的元素。<o:p></o:p>
2. 如果是因为要减少对象拷贝和赋值方面的负担,而要在容器中存放指针的话,可以考虑用boost库中的智能指针shared_ptr包装指针,达到容器中引用的语意。<o:p></o:p>
3. 如果你不希望因为使用boost::shared_ptr增加引用计数的负担,认为引入智能指针不好理解,那么你用指针作为容器的元素要千万小心,这时你要自己管理内存。<o:p></o:p>
例如: <o:p></o:p>
例 9:用boost库中的智能指针shared_ptr包装指针的例子:<o:p></o:p>
#include <iostream><o:p></o:p>
#include <sstream><o:p></o:p>
#include <string><o:p></o:p>
#include <vector><o:p></o:p>
#include <algorithm><o:p></o:p>
#include <list><o:p></o:p>
#include <boost\smart_ptr.hpp> // 要包含BOOST类库中智能指针的头文件<o:p></o:p>
using namespace std;<o:p></o:p>
class CTest {<o:p></o:p>
public:<o:p></o:p>
CTest( const string& str, int iPrice ) : m_strName( str ), m_iPrice( iPrice ) { }<o:p></o:p>
void vPrint() { cout << "name=" << m_strName << " price = " << m_iPrice << endl;<o:p></o:p>
}<o:p></o:p>
private:<o:p></o:p>
string m_strName;<o:p></o:p>
int m_iPrice;<o:p></o:p>
friend class CStrFunc;<o:p></o:p>
friend class CIntFunc;<o:p></o:p>
};<o:p></o:p>
// 函数对象,根据string比较<o:p></o:p>
class CStrFunc {<o:p></o:p>
string m_str;<o:p></o:p>
public:<o:p></o:p>
CStrFunc( const string& str ) : m_str( str ) {<o:p></o:p>
}<o:p></o:p>
// 此处要改为boost::shared_ptr<CTest>&,因为vector容器中的元素为<o:p></o:p>
// boost::shared_ptr<CTest><o:p></o:p>
bool operator() ( const boost::shared_ptr<CTest>& left ) {<o:p></o:p>
return ( m_str == (*left).m_strName ) ? true : false;<o:p></o:p>
}<o:p></o:p>
};<o:p></o:p>
// 函数对象,根据int比较<o:p></o:p>
class CIntFunc {<o:p></o:p>
int m_iPrice;<o:p></o:p>
public:<o:p></o:p>
CIntFunc( int iPrice ) : m_iPrice( iPrice ) {<o:p></o:p>
}<o:p></o:p>
// 此处要改为boost::shared_ptr<CTest>&,因为vector容器中的元素为<o:p></o:p>
// boost::shared_ptr<CTest><o:p></o:p>
bool operator() ( const boost::shared_ptr<CTest>& left ) {<o:p></o:p>
return ( m_iPrice == (*left).m_iPrice ) ? true : false;<o:p></o:p>
}<o:p></o:p>
};<o:p></o:p>
void main( ) {<o:p></o:p>
<o:p></o:p>
vector< boost::shared_ptr<CTest> > vectTest;<o:p></o:p>
int i;<o:p></o:p>
for ( i = 0; i < 5 ; i++ ) {<o:p></o:p>
stringstream stream;<o:p></o:p>
stream << i;<o:p></o:p>
string str = stream.str();<o:p></o:p>
boost::shared_ptr<CTest> ptrShare( new CTest( str, i ) );<o:p></o:p>
vectTest.push_back( ptrShare );<o:p></o:p>
}<o:p></o:p>
for ( i = 0 ; i < vectTest.size(); i++ ) {<o:p></o:p>
( *vectTest[ i ] ).vPrint();<o:p></o:p>
}<o:p></o:p>
// 删除所有m_strName = "3"的元素<o:p></o:p>
vectTest.erase( remove_if( vectTest.begin(), vectTest.end(), CStrFunc( "3" ) ),<o:p></o:p>
vectTest.end() );<o:p></o:p>
cout << "delete 3 after : " << endl;<o:p></o:p>
for ( i = 0 ; i < vectTest.size(); i++ ) {<o:p></o:p>
( *vectTest[ i ] ).vPrint();<o:p></o:p>
}<o:p></o:p>
// 删除所有m_iPrice = 2的元素<o:p></o:p>
vectTest.erase( remove_if( vectTest.begin(), vectTest.end(), CIntFunc( 2 ) ),<o:p></o:p>
vectTest.end() );<o:p></o:p>
cout << "delete 2 after : " << endl;<o:p></o:p>
for ( i = 0 ; i < vectTest.size(); i++ ) {<o:p></o:p>
( *vectTest[ i ] ).vPrint();<o:p></o:p>
}<o:p></o:p>
}<o:p></o:p>
以上代码不会导致内存泄露。<o:p></o:p>
分享到:
相关推荐
STL关联容器入门
Set 容器中元素的类型可以是任何类型,包括内置类型和用户定义类型。元素类型必须满足以下条件: * 元素类型必须支持小于运算符(<),用于比较元素的大小。 * 元素类型必须支持复制构造函数和赋值运算符,用于元素...
STL容器可以分为两大类:序列式容器和关联式容器。 序列式容器的特点是强调值的排序,每个元素均有固定的位置。常见的序列式容器有vector、list、deque等。 关联式容器的特点是无需强调元素的物理顺序,各元素之间...
关联式容器是SGI STL中的一类重要数据结构,它们允许通过键(key)来高效地查找、插入和删除元素。在本压缩包中,我们很可能会找到如`set`、`multiset`、`map`和`multimap`等关联式容器的源代码。 关联式容器的核心...
在STL中,`vector`是一种非常重要的容器,它是一个动态数组,允许在任意位置进行元素的插入和删除,并能保持元素的顺序。 `vector`容器的主要特点包括: 1. 动态数组:`vector`的底层实现是一个动态数组,这意味着...
在本文中,我们将重点讨论STL中的容器,特别是序列式容器和关联式容器。 1. 序列式容器: 序列式容器是一类按照元素插入顺序存储的容器,包括vector、queue、deque、priority_queue、list和stack。这些容器有着各自...
这些容器不像序列式容器(如vector、list)那样有明显的头部和尾部,也不提供push_back、push_front、pop_back、pop_front等操作。相反,关联式容器主要提供了对元素基于键值的快速查找、插入和删除功能,这得益于...
容器是用于存储数据的对象,STL提供的容器包括了序列式容器和关联式容器。序列式容器,如vector、list等,强调元素的顺序性,即容器中的每个元素都拥有一个固定的位置。关联式容器,如set、map等,以元素间的关联...
STL容器提供了一系列操作方法,包括构造、赋值、插入、删除、查找、容量管理等。例如: - 构造函数:初始化容器,可以指定初始容量、拷贝构造等。 - 插入操作:如push_back()(向向量尾部添加元素)、insert()(在...
STL容器都提供了一些基本的成员变量和成员函数,用于对容器中的元素进行操作。这些成员变量和成员函数包括: * size():返回容器中的元素个数。 * max_size():返回容器的最大容量。 * empty():检查容器是否为空。...
STL不仅提供容器,还有一系列通用算法,如`sort`, `find`, `copy`, `transform`等,这些算法可以作用于任何满足一定要求的序列上,极大提高了编程效率和代码的可读性。例如: - `sort`: 对容器进行排序。 - `find`: ...
在本文中,我们将重点讨论STL中的容器,特别是序列式容器和关联式容器。 1. 序列式容器: 序列式容器是一类按照元素插入顺序存储的容器,包括vector、queue、deque、priority_queue、list和stack。这些容器有着...
**容器**:在C++ STL中,容器是用来存储和组织其他对象的数据结构。`std::vector`是一个容器,能够像容器一样存放各种类型的对象。 **动态数组**:`std::vector`能够根据需要动态调整大小,这意味着当需要更多的...
在C++标准模板库(STL)中,`set`容器是一种非常重要的关联容器,主要用于存储唯一元素,并且这些元素会根据其键值自动排序。`set`内部通常采用红黑树(一种自平衡的二叉查找树)来实现,这使得它在执行插入、删除和...
在STL中,容器是一类能够存储数据的对象,包括vector、string、deque、queue、list、set、multiset、map和multimap。下面将详细介绍这些容器的使用和API方法。 1. **vector**:动态数组,可以自动扩展其大小。常用...
在标题和描述中提到的"基于stl共享内存,可以像使用STL容器一样使用共享内存",指的是通过设计一个自定义的内存分配器(Allocator),使得STL容器如vector、list、map等能够在共享内存上进行操作。这种方式的优势...
STL定义的三类容器——顺序性容器、关联式容器和容器适配器,各自拥有独特的优势和适用场景。了解并掌握这些容器的特点和使用方法对于有效地进行C++程序开发至关重要。通过合理选择合适的容器类型,可以大大提高代码...
C++实战篇:STL-容器 C++实战篇:STL-容器 C++实战篇:STL-容器 C++实战篇:STL-容器 C++实战篇:STL-容器 C++实战篇:STL-容器 C++实战篇:STL-容器 C++实战篇:STL-容器 C++实战篇:STL-容器 C++实战篇:STL-容器 ...
本文将详细介绍C++ STL中两种主要类型的容器:序列式容器与关联式容器。 #### 二、序列式容器 序列式容器是基于元素在内存中连续或接近连续存储的特点设计的,主要包括vector、deque、list等几种类型。 ##### 1. ...
`deque`(双端队列)是C++标准模板库(STL)中的一种重要容器,它提供了类似数组的功能,同时支持在两端进行高效插入和删除操作。与vector相比,deque在两端操作时通常具有更好的性能,因为它不需要移动大量元素。...