vector的clear操作的内部过程

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

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

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

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

// 清除全部元素。注意并未释放空间,以备可能未来还会新加入元素。
 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技术。

// destroy()单指针版本
template <class T>
inline void destroy(T* pointer) {
    pointer->~T();	// 唤起 dtor ~T()
}



// destroy()两迭代器版本
//利用 __type_traits<> 求取最适当措施。
template <class ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last) {
  __destroy(first, last, value_type(first));
}

//判断元素的数值型别(value type)有 non-trivial destructor(自定义析构函数)
template <class ForwardIterator, class T>
inline void __destroy(ForwardIterator first, ForwardIterator last, T*) {
  typedef typename __type_traits<T>::has_trivial_destructor trivial_destructor;
  __destroy_aux(first, last, trivial_destructor());
}
// 如果元素的数值型别(value type)有 non-trivial destructor(自定义析构函数)
template <class ForwardIterator>
inline void
__destroy_aux(ForwardIterator first, ForwardIterator last, __false_type) {
 for ( ; first < last; ++first)    //遍历元素进行析构
    destroy(&*first);                  //!!!!!关键句!!!!!!!!!
}

//如果元素的数值型别(value type)有trivial destructor
template <class ForwardIterator> 
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 <class T1, class T2>
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];

 

       下面进行一下测试

#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
class Test
{
private:
	int m_a;
public:
    Test(int a):m_a(a){}
    ~Test() { cout << "Test des" << endl; }
};
 
int main()
{
    vector<Test> 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的构造与内存管理。




  • 10
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值