vector clear 内部过程
来源:互联网 发布:企汇网发布信息软件 编辑:程序博客网 时间:2024/06/03 16:52
最近在论坛看到一个提问帖子,问题是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;
- }
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;
- }
// 清除全部元素。注意并未释放空间,以备可能未来还会新加入元素。 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);
- }
// 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 destructortemplate <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;
- }
#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的构造与内存管理。
0 0
- vector clear 内部过程
- vector的clear操作的内部过程
- vector的clear操作的内部过程
- vector的clear操作的内部过程
- vector的clear操作的内部过程
- vector的clear()的内部过程与析构函数调用
- vector的clear()的内部过程与析构函数调用
- vector::clear
- vector::clear()
- vector::clear
- vector::clear
- vector::clear
- std::vector::clear
- std::vector::clear
- vector::clear(),容器vector的clear函数详解。
- vector的内部实现
- vector内存清理情况 clear和swap
- STL vector中的clear方法(18)
- 这个循环让我混乱了,希望懂的人指点一下
- poj 2524 Ubiquitous Religions(并查集)
- Android广播机制
- VS2010编译Project时会出“error LNK1123” 错误
- 服务器大量的last
- vector clear 内部过程
- 查看mysql版本的四种方法
- canvas 像素操作
- 13.3 无意识的递归
- debian系统安装Thinkpad T410s的无线网卡驱动:centrino Advanced-N 6200 2x2 AGN
- 010004 在选择中挣扎
- UICollectionView的使用
- ShareSDK上线运营统计、手游录像、短信验证码三大功能
- 13.2 重载"+"与StringBuilder