C++标准模板库中的auto_ptr
来源:互联网 发布:win10和mac os 编辑:程序博客网 时间:2024/06/01 10:19
原帖地址 : http://blog.csdn.net/wcyoot/article/details/6546375
标准模板库源代码:
namespace std{// 特殊类,用于non-const auto_ptrs的拷贝和赋值// 由于auto_ptr的拷贝构造、赋值运算都需要使用引用传递参数(否则会照成指针所有权并没有真正移交)// 因此需要支持当临时右值作为拷贝和赋值的功能// auto_ptr_ref设计目的:用来实现上述情形,如:// auto_ptr<int> ap1 = auto_ptr<int>(new int(8));//等号右边的是一个临时右值// auto_ptr<int> fun()//一个生成auto_ptr<int>的source函数// auto_ptr<int> ap2 ( fun() );//调用fun()生成的auto_ptr<int>是临时右值// 即支持将auto_ptr作为临时右值使用。template<class _Ty>struct auto_ptr_ref{// proxy reference for auto_ptr copyingexplicit auto_ptr_ref(_Ty *_Right)// explicit 说明该构造函数不能进行隐式类型转换: _Ref(_Right){// construct from generic pointer to auto_ptr ptr}_Ty *_Ref;// generic pointer to auto_ptr ptr};template<class _Ty>class auto_ptr{// wrap an object pointer to ensure destructionpublic:typedef _Ty element_type;// 显式构造函数,不支持从普通ptr到auto_ptr的隐式转换,确保其安全性explicit auto_ptr(_Ty *_Ptr = 0) _THROW0(): _Myptr(_Ptr){// construct from object pointer}// 构造时获取对某个对象的所有权(ownership),在析构时释放该对象。auto_ptr(auto_ptr<_Ty>& _Right) _THROW0(): _Myptr(_Right.release()){// construct by assuming pointer from _Right auto_ptr}// 构造时获取对某个对象的所有权(ownership),在析构时释放该对象。// 注意:此处是值传递,所以可以用来传入右值auto_ptr(auto_ptr_ref<_Ty> _Right) _THROW0(){// construct by assuming pointer from _Right auto_ptr_ref_Ty *_Ptr = _Right._Ref;_Right._Ref = 0;// release old_Myptr = _Ptr;// reset this}// 类型转换,使得类的继承关系得以支持,如果两个类型不能进行转换,编译时将会得到警告或错误template<class _Other>operator auto_ptr<_Other>() _THROW0(){// convert to compatible auto_ptrreturn (auto_ptr<_Other>(*this));}// 类型转换,使得类的继承关系得以支持template<class _Other>operator auto_ptr_ref<_Other>() _THROW0(){// convert to compatible auto_ptr_ref_Other *_Cvtptr = _Myptr;// test implicit conversionauto_ptr_ref<_Other> _Ans(_Cvtptr);_Myptr = 0;// pass ownership to auto_ptr_refreturn (_Ans);}// 带类型转换的赋值运算符重载,可能需要释放当前资源template<class _Other>auto_ptr<_Ty>& operator=(auto_ptr<_Other>& _Right) _THROW0(){// assign compatible _Right (assume pointer)reset(_Right.release());return (*this);}// 拷贝构造函数,转移指针所有权template<class _Other>auto_ptr(auto_ptr<_Other>& _Right) _THROW0(): _Myptr(_Right.release()){// construct by assuming pointer from _Right}// 赋值运算符重载auto_ptr<_Ty>& operator=(auto_ptr<_Ty>& _Right) _THROW0(){// assign compatible _Right (assume pointer)reset(_Right.release());return (*this);}// 赋值运算符重载auto_ptr<_Ty>& operator=(auto_ptr_ref<_Ty> _Right) _THROW0(){// assign compatible _Right._Ref (assume pointer)_Ty *_Ptr = _Right._Ref;_Right._Ref = 0;// release oldreset(_Ptr);// set newreturn (*this);}// 析构时释放资源,它是安全的~auto_ptr(){// destroy the objectif (_Myptr != 0)delete _Myptr;}// 基本操作:*运算符_Ty& operator*() const _THROW0(){// return designated value#if _HAS_ITERATOR_DEBUGGINGif (_Myptr == 0)_DEBUG_ERROR("auto_ptr not dereferencable");#endif /* _HAS_ITERATOR_DEBUGGING */__analysis_assume(_Myptr);return (*get());}// 基本操作:->运算符_Ty *operator->() const _THROW0(){// return pointer to class object#if _HAS_ITERATOR_DEBUGGINGif (_Myptr == 0)_DEBUG_ERROR("auto_ptr not dereferencable");#endif /* _HAS_ITERATOR_DEBUGGING */return (get());}// 辅助函数:显式的返回auto_ptr所拥有的对象指针_Ty *get() const _THROW0(){// return wrapped pointerreturn (_Myptr);}// 辅助函数:用来转移所有权_Ty *release() _THROW0(){// return wrapped pointer and give up ownership_Ty *_Tmp = _Myptr;_Myptr = 0;return (_Tmp);}// 辅助函数:用来接收所有权void reset(_Ty* _Ptr = 0){// destroy designated object and store new pointerif (_Ptr != _Myptr && _Myptr != 0)delete _Myptr;_Myptr = _Ptr;}private:_Ty *_Myptr;// the wrapped object pointer};}
1、 构造函数与析构函数
auto_ptr在构造时获取对某个对象的所有权(ownership),在析构时释放该对象。我们可以这样使用auto_ptr来提高代码安全性:
int* p = new int(0);auto_ptr<int> ap(p);
从此我们不必关心应该何时释放p,也不用担心发生异常会有内存泄漏。
这里我们有几点要注意:
1) 因为auto_ptr析构的时候肯定会删除他所拥有的那个对象,因此两个auto_ptr不能同时拥有同一个对象。像这样:
int* p = new int(0);auto_ptr<int> ap1(p);auto_ptr<int> ap2(p);// 危险!!p将会被释放两次
因为ap1与ap2都认为指针p是归它管的,在析构时都试图删除p, 两次删除同一个对象的行为在C++标准中是未定义的。所以我们必须防止这样使用auto_ptr.
2) 考虑下面这种用法:
int* pa = new int[10];auto_ptr<int> ap(pa); // 危险!!auto_ptr中删除指针用的是delete而不是delete[]
因为auto_ptr的析构函数中删除指针用的是delete,而不是delete [],所以我们不应该用auto_ptr来管理一个数组指针。
3) 构造函数的explicit关键词有效阻止从一个“裸”指针隐式转换成auto_ptr类型。
4) C++保证删除一个空指针是安全的,析构函数是安全的。
2、拷贝构造与赋值
与引用计数型智能指针不同的,auto_ptr要求其对“裸”指针的完全占有性。也就是说一个”裸“指针不能同时被两个以上的auto_ptr所拥有。那么,在拷贝构造或赋值操作时,我们必须作特殊的处理来保证这个特性。auto_ptr的做法是“所有权转移”,即拷贝或赋值的源对象将失去对“裸”指针的所有权,所以auto_ptr的拷贝构造函数,赋值函数的参数为引用而不是常引用(const reference)。当然,一个auto_ptr也不能同时拥有两个以上的“裸”指针,所以,拷贝或赋值的目标对象将先释放其原来所拥有的对象。
这里的注意点是:
1) 因为一个auto_ptr被拷贝或被赋值后, 其已经失去对原对象的所有权,这个时候,对这个auto_ptr的提领(dereference)操作是不安全的。
int* p = new int(0);auto_ptr<int> ap1(p);auto_ptr<int> ap2 = ap1;cout<<*ap1; //错误,此时ap1只剩一个null指针在手了
这种情况较为隐蔽的情形出现在将auto_ptr作为函数参数按值传递,因为在函数调用过程中在函数的作用域中会产生一个局部对象来接收传入的auto_ptr(拷贝构造),这样,传入的实参auto_ptr就失去了其对原对象的所有权,而该对象会在函数退出时被局部auto_ptr删除。如下:
void f(auto_ptr<int> ap){cout<<*ap;}auto_ptr<int> ap1(new int(0));f(ap1);cout<<*ap1; //错误,经过f(ap1)函数调用,ap1已经不再拥有任何对象了。
因此,auto_ptr作为函数参数按值传递是一定要避免的。或许大家会想到用auto_ptr的指针或引用作为函数参数或许可以,但是仔细想想,我们并不知道在函数中对传入的auto_ptr做了什么, 如果当中某些操作使其失去了对对象的所有权, 那么这还是可能会导致致命的执行期错误。也许,用const reference的形式来传递auto_ptr会是一个不错的选择。
2)我们可以看到拷贝构造函数与赋值函数都提供了一个成员模板在不覆盖“正统”版本的情况下实现auto_ptr的隐式转换。因此可以实现继承类指针到基类指针的转换。
3)因为auto_ptr不具有值语义(value semantic), 所以auto_ptr不能被用在stl标准容器中。
所谓值语义,是指符合以下条件的类型(假设有类A):
A a1;
A a2(a1);
A a3;
a3 = a1;
那么
a2 == a1, a3 == a1
很明显,auto_ptr不符合上述条件,而我们知道stl标准容器要用到大量的拷贝赋值操作,并且假设其操作的类型必须符合以上条件。
3、 提领操作(dereference)
即“*运算符”和“->运算符”。首先要确保这个智能指针确实拥有某个对象,否则,这个操作的行为即对空指针的提领是未定义的。
4、辅助函数
1) get用来显式的返回auto_ptr所拥有的对象指针。标准库提供的auto_ptr既不提供从“裸”指针到auto_ptr的隐式转换(构造函数为explicit),也不提供从auto_ptr到“裸”指针的隐式转换,从使用上来讲可能不那么的灵活, 考虑到其所带来的安全性还是值得的。
2) release,用来转移所有权
3) reset,用来接收所有权,如果接收所有权的auto_ptr如果已经拥有某对象,必须先释放该对象。
5、特殊转换--auto_ptr_ref类相关
由于auto_ptr的拷贝构造、赋值运算都需要使用引用传递参数(否则会照成指针所有权并没有真正移交)
因此需要支持当临时右值作为拷贝和赋值的功能
设计auto_ptr_ref的目的:用来实现上述情形,如:
auto_ptr<int> ap1 = auto_ptr<int>(new int(8));//等号右边的是一个临时右值auto_ptr<int> fun()//一个生成auto_ptr<int>的source函数auto_ptr<int> ap2 ( fun() );//调用fun()生成的auto_ptr<int>是临时右值
引入auto_ptr_ref来实现从右值向左值的转换。其过程为:
1)auto_ptr<int>(new int(8))调用构造函数生成一个临时的auto_ptr对象
2)编译器发现ap1的构造函数无法匹配参数
3)发现辅助的构造函数auto_ptr(auto_ptr_ref<_Ty> _Right) ,调用隐式类型转换auto_ptr_ref()将该临时对象隐式转换为一个auto_ptr_ref对象
4)调用辅助构造函数auto_ptr(auto_ptr_ref<_Ty> _Right) 生成ap1
- C++标准模板库中的auto_ptr
- C++标准模板库中的auto_ptr
- C++标准模板库中的auto_ptr
- [C++标准模板库:自修教程与参考手册]关于auto_ptr
- STL标准程序库第一部分总结(Auto_ptr&&numeric_limits,标准模板库,迭代器的配接器)
- C++中的标准模板库STL及容器
- C++:标准模板库(STL)
- C++:标准模板库vector
- C++:标准模板库map
- C++:标准模板库string
- C++:标准模板库Sort
- C++STL标准模板库
- [C/C++标准库]_[初级]_[使用auto_ptr智能指针]
- C++标准库智能指针(std::auto_ptr)
- C++标准库智能指针(std::auto_ptr)
- C++标准库auto_ptr指针的应用
- C++标准库:智能指针auto_ptr
- C++标准库智能指针(std::auto_ptr)
- 异常处理:Eclipse下解决Plugin execution not covered by lifecycle configuration异常
- Android的NDK开发(2)————利用Android NDK编写一个简单的HelloWorld
- How to create new view by using cleartool command in Clearcase?
- 前端实用的东西--持续更新
- 淘宝的十年技术之路
- C++标准模板库中的auto_ptr
- JS 数组扩展函数--求起始项到终止项和
- 30秒搭建Github Page
- 安卓开发者必备的小软件(全是干货)
- Android的NDK开发(4)————JNI数据结构之JNINativeMethod
- 免费下载ColorSchemer Studio(带注册码有效免费key)-非常好用的配色工具
- 程序员如何留住健康
- Linux strace命令
- Linux下使用Iptable实现Soft AP(无线软热点)。