vector的clear操作的内部过程

来源:互联网 发布:大学生单片机自学视频 编辑:程序博客网 时间:2024/06/05 23:49
原型:
#include <vector>
void clear();
函数clear()删除储存在vector中的所有元素. 如果vector的元素是一些object, 则它将为当前储存的每个元素调用它们各自的析构函数(destructor). 然而, 如果vector储存的是指向对象的指针, 此函数并不会调用到对应的析构函数. 在第二种情况下, 为了完全删除vector中的元素则应使用一个类似于下的循环:
    std::vector<SomeObject*> aVector;
    //The elements of the vector are created with the operand 'new' at some point in the program
    [...]
    for(int i=0 ; i<aVector.size() ; i++)
        delete aVector[i];
    aVector.clear();
调用clear之后, vector的尺寸(size)将变成zero. 但它的容量(capacity)却并不发生变化, vector本身并不释放任何内存.

如果你想同时做到清空vector的元素和释放vector的容量, 你可以使用swap技巧(此技巧并非在所有环境中都管用 e.g. not with Intel Compiler 10.0.69 and LINUX 2.6.9-89 x64):
    std::vector aVector;
    [...]
    aVector.swap( std::vector() );
这样做会创建一个临时的空vector, 它将替换希望清空的vector.

clear()以线性时间linear time运行.
最近在论坛看到一个提问帖子,问题是vector中存储了对象的指针,调用clear后这些指针如何删除?

[cpp] view plaincopy
  1. class Test  
  2. {  
  3. public:  
  4.     Test() {}  
  5.     ~Test() { cout << "Test des" << endl; }  
  6. };  
  7.    
  8. int main()  
  9. {  
  10.     vector<Test*> vec;  
  11.     vec.push_back(new Test());  
  12.     vec.push_back(new Test());  
  13. vec.push_back(new Test());  
  14. //对象如何进行释放,要调用已定义析构函数  
  15.     vec.clear();  
  16.     return 0;  
  17. }  

同时最近又看到一道面试题:对于STL中的vector调用clear时,内部是如何操作的?若想将其内存释放,该如何操作?

      针对以上两个问题,我们追踪一下STL源码。

[cpp] view plaincopy
  1. // 清除全部元素。注意并未释放空间,以备可能未来还会新加入元素。  
  2.  void clear() { erase(begin(), end()); }  
  3. //调用vector::erase的两迭代器范围版本  
  4.     iterator erase(iterator first, iterator last) {  
  5.         iterator i = copy(last, finish, first);  
  6.   //finish在vector中定义表示目前使用空间的尾,相当于end(),clear调用时last=finish  
  7.         destroy(i, finish); //全局函数,结构的基本函数  
  8.         finish = finish - (last - first);  
  9.         return first;  
  10. }  

以上关键就是调用了destroy函数。destory函数在 <stl_construct.h>中定义,为了便于分析整个的构造与释放,将construct函数的内容也进行了摘录。这其中要注意的是traits技术。

[cpp] view plaincopy
  1. // destroy()单指针版本  
  2. template <class T>  
  3. inline void destroy(T* pointer) {  
  4.     pointer->~T();   // 唤起 dtor ~T()  
  5. }  
  6.   
  7.   
  8.   
  9. // destroy()两迭代器版本  
  10. //利用 __type_traits<> 求取最适当措施。  
  11. template <class ForwardIterator>  
  12. inline void destroy(ForwardIterator first, ForwardIterator last) {  
  13.   __destroy(first, last, value_type(first));  
  14. }  
  15.   
  16. //判断元素的数值型别(value type)有 non-trivial destructor(自定义析构函数)  
  17. template <class ForwardIterator, class T>  
  18. inline void __destroy(ForwardIterator first, ForwardIterator last, T*) {  
  19.   typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;  
  20.   __destroy_aux(first, last, trivial_destructor());  
  21. }  
  22. // 如果元素的数值型别(value type)有 non-trivial destructor(自定义析构函数)  
  23. template <class ForwardIterator>  
  24. inline void  
  25. __destroy_aux(ForwardIterator first, ForwardIterator last, __false_type) {  
  26.  for ( ; first < last; ++first)    //遍历元素进行析构  
  27.     destroy(&*first);                  //!!!!!关键句!!!!!!!!!  
  28. }  
  29.   
  30. //如果元素的数值型别(value type)有trivial destructor  
  31. template <class ForwardIterator>   
  32. inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {}  
  33. //什么都不做,STL是用了一种保守的方式,只有内建的元素类型(int,float等)进行判定trivial destructor的时候才是__true_type其他一切用户自定义类型都是__false_type  
  34.   
  35.   
  36. // destroy()两迭代器版本,针对char*与wchar_t*的特化版本  
  37. inline void destroy(char*, char*) {}  
  38. inline void destroy(wchar_t*, wchar_t*) {}  
  39.   
  40. //仅仅是对placement new 的一层封装  
  41. template <class T1, class T2>  
  42. inline void construct(T1* p, const T2& value) {  
  43.   new (p) T1(value);    // placement new; 唤起 ctor T1(value);  
  44. }  

看到这里基本对上述的问题已经有答案了。

        由于对象的指针不是内建对象,所以进行遍历析构。

for ( ; first <last; ++first)    //遍历元素进行析构

destroy(&*first);                  //!!!!!关键句!!!!!!!!!

*iterator是元素类型,&*iterator是元素地址,也就是一个指针。之后调用&*iterator->~T();所以可知当vector中所存储的元素为对象的时候,调用clear()操作的时候系统会自动调用析构函数。但是当存储元素是指针的时候,指针指向的对象就没法析构了。因此需要释放指针所指对象的话,需要在clear操作之前调用delete。

        for(i= 0; i < vItem.size();i++)

             delete vItem[i];

 

       下面进行一下测试

[cpp] view plaincopy
  1. #include <cstdio>  
  2. #include <iostream>  
  3. #include <vector>  
  4. using namespace std;  
  5. class Test  
  6. {  
  7. private:  
  8.     int m_a;  
  9. public:  
  10.     Test(int a):m_a(a){}  
  11.     ~Test() { cout << "Test des" << endl; }  
  12. };  
  13.    
  14. int main()  
  15. {  
  16.     vector<Test> vec;  
  17.     Test* p1=new Test(1);  
  18.     Test* p2=new Test(2);  
  19.     Test* p3=new Test(3);  
  20.     vec.push_back(*p1);  
  21.     vec.push_back(*p2);  
  22.     vec.push_back(*p3);  
  23.     vec.clear();  
  24.     return 0;  
  25. }  

为什么调用了6次析构函数?(提示,vector的动态增长。)参见我的博客:vector的构造与内存管理。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 京东的货运代理怎么办 天天练推广期没了怎么办 微信自动建群怎么办 刚刚不小心扫了无痕爆客怎么办 苹果6升级卡死怎么办 随行付换手机了怎么办 融e联账号冻结怎么办 58同城高危账户怎么办 网购迟迟不发货怎么办 优酷不能投屏了怎么办 爱尚街借款不还怎么办 小米商城买东西没收到货怎么办 微信投票地区限制怎么办 微信退款未到账怎么办 微信钱包锁忘了怎么办 xp系统管理员密码忘了怎么办 沃尔沃menu键没反应怎么办 微信转账受限制怎么办 被米虎网骗了手里还有合同怎么办 学校要求上传论文pdf格式怎么办 备份的Wifi密码查看乱码怎么办 u盘密码忘了怎么办 京东会员号被黑怎么办 淘宝企业店铺三证不合一怎么办 淘宝企业店铺营业执照注销了怎么办 不想开淘宝企业店铺了怎么办 id图片跨页排版怎么办 合约机不想要了怎么办? 移动A3手机老卡怎么办 中国移动手机a3很卡怎么办 移动手机a4好卡怎么办 红米手机卡顿反应慢怎么办 红米3s网速慢怎么办 红米4a内存不足怎么办 红米3s手机发热怎么办 魅蓝s6信号差怎么办 oppo手机媒体音量没声音怎么办 红米note3反应慢怎么办 红米4g信号差怎么办 红米4g网速慢怎么办 红米24g信号不好怎么办