最近看了下STL,用的过程中有一些体会需要记一下。
容器的空间申请和基本函数操作,以及algorithm等都比较好理解,用起来也很方便,比较关键的是容器元素包含指针时,空间的申请和释放问题,这个觉得STL做得挺乱的。总结了几点注意的。
1)自己new的空间,在释放的时候必须先delete,然后再释放容器。例如list<char*> MS,链表中存的是自己的动态字符串,如果字符串是自己动态申请的,则在释放该链表的时候,需要先delete [](*curIter),然后再MS.erase(curIter),其中curIter是当前迭代器。
2)list的成员函数erase、remove和clear都会自动调用元素各自的析构函数,所以如果元素是自己定义的类,并且有完善的析构函数,则直接删除即可。这类链式存储,一个元素一个元素递增空间的结构,这些函数可以真正地改变list占用的内存大小。
3)vector等的空间释放方式。需要注意两点:
A、理解erase-remove惯用法,包括erase和remove函数的返回值等,http://blog.csdn.net/peteryxk/article/details/1804696这篇文章中讲的比较清楚,下面是一个代码示例:
1 /*删除vector对象vec中等于10的元素,第一种方法*/ 2 for ( begin = vec.begin() ; begin != vec.end() ; /* ++begin */ ) 3 { 4 if ( 10 == *begin ) 5 { 6 begin = vec.erase( begin ) ; 7 } 8 else 9 { 10 ++begin ; 11 } 12 } 13 /*remove-erase方法*/ 14 vec.erase(remove (vec.begin() ,vec.end(),10) , vec.end()) ;
需要搞明白remove和erase在这种顺序结构中的工作原理。
B、由于vector的空间是阶梯递增式管理的,而且基本只增不减,也就是,虽然调用remove、erase或者clear等方法(他们会调用所存元素对象的析构函数,如果元素是用户定义的类,并且有完善析构函数释放掉该类的对象动态申请的空间,则remove和erase确实会释放掉一些内存,但是容器本身的空间还是难以被利用),容器之前分配的空间仍不会被回收,大小不变,仍旧不能被其他程序使用,这是由STL的内存管理机制决定的,目的是为了提高效率。那么应该怎么回收vector的内存呢?这里就用了一个小的技巧,swap方法,代码如下:
{ std::vector<int> tmp; vec.swap(tmp); }//使用一个局部变量空的容器temp,与vec交换,退出temp作用域后,temp会释放自己的空间,而此时vec已经是空的容器
list由于是链式存储的,跟vector机制不一样,他的成员函数remove、erase、pop_front、pop_back和clear等都会回收被删除元素的内存空间,不需要swap协助。
对于vector,作如下实验就可以看到,它的空间其实一直还是保留着的,除非swap掉:
1 vector<int> vec; 2 3 for(int i=1;i<=10;i++) 4 { 5 vec.push_back(i); 6 cout<<vec.size()<<" "<<vec.capacity()<<" "<<vec.max_size()<<endl; 7 } 8 cout<<endl; 9 for(int i=1;i<=10;i++) 10 { 11 vec.erase(remove(vec.begin(),vec.end(),i),vec.end()); 12 cout<<vec.size()<<" "<<vec.capacity()<<endl; 13 } 14 cout<<endl; 15 if(true) 16 { 17 vector<int> temp; 18 vec.swap(temp); 19 } 20 cout<<vec.size()<<" "<<vec.capacity()<<endl;
运行结果如下:
4)下面给出erase(删除迭代器区间的内容)和remove函数(一般用来删除容器中等于特定值的内容)的返回值定义,以方便理解3)A.
List::erase() Return value:
A bidirectional iterator pointing to the new location of the element that followed the last element erased by the function call, which is the list end if the operation erased the last element in the sequence.
List::remove() Return value: None
Vector::erase() Return value:
A random access iterator pointing to the new location of the element that followed the last element erased by the function call, which is the vector end if the operation erased the last element in the sequence.
非成员函数,算法库中的remove() Return value:
A forward iterator pointing to the new end of the range that includes all the elements with a value that does not compare equal to value.
5)关于STL的内存管理,有一篇文章http://philoscience.iteye.com/blog/1456509中好像说得挺清楚的,有空再看看。