文件memory中第848行 - 975行是auto_ptr的全部定义,如需查看源码请转看本文末尾的附录。auto_ptr的作用不必多说,它在拷贝构造和赋值操作时的“所有权”转移也被人熟知也不再赘述,本文主要是希望通过剖析STL auto_ptr的源码来透视auto_ptr定义背后的思想。
auto_ptr作为比较简单的智能指针,需要处理5种指针行为,接下来我将分别对它们进行阐述。
(1) 构造:
由构造函数来实现,为智能指针指定目标物,即内建指针;默认设目标物为0,从而避免“野指针”带来的错误。构造函数很容易理解,需要警惕的是:如果构造函数是单个参数的,很可能被编译当作隐式类型转换函数来使用。如果你更喜欢完全控制程序的行为,可以禁止编译器悄悄行动,只要用explicit修饰构造函数即可。auto_ptr就采用了这样的方式。
(2) 析构
析构的作用即释放内存空间,由于auto_ptr未引入应用计数,在析构函数中直接释放内存空间即可,不会带来问题。
(3) 拷贝
拷贝即copy constructor,严格说它也应该归纳到构造中去,不过它的行为方式与普通构造有很大的不同。拷贝构造函数的参数是一个智能指针的对象。由于auto_ptr涉及到“所有权”转移问题,因此auto_ptr的拷贝构造函数的形参并没有被修饰为const,因为“所有权”转移将对原对象做修改。
(4) 赋值
赋值即assignment operator,也就是等号操作符。赋值操作符函数的参数也是一个智能指针对象,同样因为“所有权”转移问题并未被修饰为const。赋值操作符函数中需要对智能指针原有的资源进行回收,因此需要先做一个安全性判断然后再释放内存资源。这个过程被封装到release函数中。
(5) 提领
提领即dereference,也称解引用。说白了就是要重载operator*和operator->使智能指针对象有内建指针一样的提领行为。它们的公共操作被封装到get函数中。
以上是最基本的5种指针行为,纵观auto_ptr源码,大部分也是围绕这5种指针行为来编写的,然而有两处可能让你觉得很困扰:
(1) operator auto_ptr<_Other>()函数
(2) auto_ptr_ref结构体
实际上operator auto_ptr<_Other>函数是用来进行隐式类型转换的,由编译器自动调用;auto_ptr_ref是专门用来解决智能指针的右值引用问题,也由编译器自动调用。这个部分的分析说明通用性比较差,如有疑问可以共同交流,这里就容我偷偷懒略去分析了。
附录:STL auto_ptr源码
template<class _Ty> struct auto_ptr_ref { // proxy reference for auto_ptr copying explicit auto_ptr_ref(_Ty *_Right) : _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 destruction public: typedef auto_ptr<_Ty> _Myt; typedef _Ty element_type; explicit auto_ptr(_Ty *_Ptr = 0) _THROW0() : _Myptr(_Ptr) { // construct from object pointer } auto_ptr(_Myt& _Right) _THROW0() : _Myptr(_Right.release()) { // construct by assuming pointer from _Right auto_ptr } 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_ptr return (auto_ptr<_Other>(*this)); } ///////////////////////////////////////////////////////////// // 当auto_ptr的拷贝构造函数以及赋值操作符函数的参数是auto_ptr- // 右值引用对象时,该参数将被转换为 auto_ptr_ref // 编译器正是通过调用下面的隐式类型转换函数来完成这一隐式转换的 ///////////////////////////////////////////////////////////// template<class _Other> operator auto_ptr_ref<_Other>() _THROW0() { // convert to compatible auto_ptr_ref _Other *_Cvtptr = _Myptr; // test implicit conversion auto_ptr_ref<_Other> _Ans(_Cvtptr); _Myptr = 0; // pass ownership to auto_ptr_ref return (_Ans); } template<class _Other> _Myt& 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 } _Myt& operator=(_Myt& _Right) _THROW0() { // assign compatible _Right (assume pointer) reset(_Right.release()); return (*this); } _Myt& operator=(auto_ptr_ref<_Ty> _Right) _THROW0() { // assign compatible _Right._Ref (assume pointer) _Ty *_Ptr = _Right._Ref; _Right._Ref = 0; // release old reset(_Ptr); // set new return (*this); } ~auto_ptr() { // destroy the object delete _Myptr; } _Ty& operator*() const _THROW0() { // return designated value #if _ITERATOR_DEBUG_LEVEL == 2 if (_Myptr == 0) _DEBUG_ERROR("auto_ptr not dereferencable"); #endif /* _ITERATOR_DEBUG_LEVEL == 2 */ return (*get()); } _Ty *operator->() const _THROW0() { // return pointer to class object #if _ITERATOR_DEBUG_LEVEL == 2 if (_Myptr == 0) _DEBUG_ERROR("auto_ptr not dereferencable"); #endif /* _ITERATOR_DEBUG_LEVEL == 2 */ return (get()); } _Ty *get() const _THROW0() { // return wrapped pointer return (_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 pointer if (_Ptr != _Myptr) delete _Myptr; _Myptr = _Ptr; } private: _Ty *_Myptr; // the wrapped object pointer };