博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
vector clear 内部过程
阅读量:2224 次
发布时间:2019-05-08

本文共 5363 字,大约阅读时间需要 17 分钟。

 最近在论坛看到一个提问帖子,问题是vector中存储了对象的指针,调用clear后这些指针如何删除?

[cpp]
  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. }  
class Test{public:    Test() {}    ~Test() { cout << "Test des" << endl; }}; int main(){    vector
vec; vec.push_back(new Test()); vec.push_back(new Test());vec.push_back(new Test());//对象如何进行释放,要调用已定义析构函数 vec.clear(); return 0;}

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

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

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

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

[cpp]
  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. }  
// destroy()单指针版本template 
inline void destroy(T* pointer) { pointer->~T(); // 唤起 dtor ~T()}// destroy()两迭代器版本//利用 __type_traits<> 求取最适当措施。template
inline void destroy(ForwardIterator first, ForwardIterator last) { __destroy(first, last, value_type(first));}//判断元素的数值型别(value type)有 non-trivial destructor(自定义析构函数)template
inline void __destroy(ForwardIterator first, ForwardIterator last, T*) { typedef typename __type_traits
::has_trivial_destructor trivial_destructor; __destroy_aux(first, last, trivial_destructor());}// 如果元素的数值型别(value type)有 non-trivial destructor(自定义析构函数)template
inline void__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type) { for ( ; first < last; ++first) //遍历元素进行析构 destroy(&*first); //!!!!!关键句!!!!!!!!!}//如果元素的数值型别(value type)有trivial destructortemplate
inline void __destroy_aux(ForwardIterator, ForwardIterator, __true_type) {}//什么都不做,STL是用了一种保守的方式,只有内建的元素类型(int,float等)进行判定trivial destructor的时候才是__true_type其他一切用户自定义类型都是__false_type// destroy()两迭代器版本,针对char*与wchar_t*的特化版本inline void destroy(char*, char*) {}inline void destroy(wchar_t*, wchar_t*) {}//仅仅是对placement new 的一层封装template
inline void construct(T1* p, const T2& value) { new (p) T1(value); // placement new; 唤起 ctor T1(value);}

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

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

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]
  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. }  
#include 
#include
#include
using namespace std;class Test{private: int m_a;public: Test(int a):m_a(a){} ~Test() { cout << "Test des" << endl; }}; int main(){ vector
vec; Test* p1=new Test(1); Test* p2=new Test(2); Test* p3=new Test(3); vec.push_back(*p1); vec.push_back(*p2); vec.push_back(*p3); vec.clear(); return 0;}

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

转载地址:http://fkafb.baihongyu.com/

你可能感兴趣的文章
A星算法详解(个人认为最详细,最通俗易懂的一个版本)
查看>>
利用栈实现DFS
查看>>
(PAT 1019) General Palindromic Number (进制转换)
查看>>
(PAT 1073) Scientific Notation (字符串模拟题)
查看>>
(PAT 1080) Graduate Admission (排序)
查看>>
Play on Words UVA - 10129 (欧拉路径)
查看>>
mininet+floodlight搭建sdn环境并创建简答topo
查看>>
【linux】nohup和&的作用
查看>>
Set、WeakSet、Map以及WeakMap结构基本知识点
查看>>
【NLP学习笔记】(一)Gensim基本使用方法
查看>>
【NLP学习笔记】(二)gensim使用之Topics and Transformations
查看>>
【深度学习】LSTM的架构及公式
查看>>
【python】re模块常用方法
查看>>
剑指offer 19.二叉树的镜像
查看>>
剑指offer 20.顺时针打印矩阵
查看>>
剑指offer 21.包含min函数的栈
查看>>
剑指offer 23.从上往下打印二叉树
查看>>
剑指offer 25.二叉树中和为某一值的路径
查看>>
剑指offer 60. 不用加减乘除做加法
查看>>
Leetcode C++《热题 Hot 100-14》283.移动零
查看>>