本文基于4.9.0版本gcc,本文代码路径:gcc-4.9.0\libstdc++-v3\include\backward\auto_ptr.h
类结构
auto_ptr的类图如下所示
它只包含一个指针成员,提供了6个成员函数,如下表所示
operator = | 拷贝一个auto_ptr后释放源auto_ptr |
operator * | 解引用对象 |
operator -> | 解引用对象成员 |
release | 释放auto_ptr |
get | 获取指针 |
reset | 释放对象指针后设置新值 |
构造函数
explicit
auto_ptr(element_type* __p = 0) throw() : _M_ptr(__p) { }
auto_ptr(auto_ptr& __a) throw() : _M_ptr(__a.release()) { }
template<typename _Tp1>
auto_ptr(auto_ptr<_Tp1>& __a) throw() : _M_ptr(__a.release()) { }
代码比较简单,element_type就是模板类型,指针指向的对象的类型。其中需要注意的在它的拷贝构造函数中是是调用release成员函数,auto_ptr讨论比较多的一个缺陷就是和这个release操作有关,我们看一下这个release成员函数干了些什么。
element_type*
release() throw()
{
element_type* __tmp = _M_ptr;
_M_ptr = 0;
return __tmp;
}
可以看到,release会返回_M_ptr指针,并把它置空。对于拷贝构造函数我们通常只是对源对象进行复制,不会改变源对象,但是auto_ptr的拷贝构造函数调用源对象的release函数来给_M_ptr赋值后,源对象的_M_ptr就会被值为NULL变成一个悬空指针。这种做法跟通常理解的拷贝行为是不一致的(拷贝通常不会修改原数据),而这样的行为在一些场合下可能是很危险的。也是这个原因导致在C++11之后不建议再使用auto_ptr。
析构函数
析构函数十分简单,就是delete一下_M_ptr释放资源。auto_ptr是一个RAII类,最大的特点就是能够自动释放内存,具体实现就是在析构函数中释放内存,这样当auto_ptr对象在离开它的作用域之后内存就会被自动释放,避免造成内存泄漏。
~auto_ptr() { delete _M_ptr; }
operator =
’operator =’也和拷贝构造函数有同样的问题,执行’operator =‘之后源对象也会被置为NULL。
auto_ptr&
operator=(auto_ptr& __a) throw()
{
reset(__a.release());
return *this;
}
template<typename _Tp1>
auto_ptr&
operator=(auto_ptr<_Tp1>& __a) throw()
{
reset(__a.release());
return *this;
}
偏特化版本
auto_ptr是个模板类,声明的时候需要指定模板类型,但如果模板类型为void怎么办?这就需要一个void类型的偏特化版本。
template<>
class auto_ptr<void>
{
public:
typedef void element_type;
} _GLIBCXX_DEPRECATED;
解引用操作
auto_ptr有*和->这两个操作,operator *返回一个指针指向的对象,->返回对象的成员。
element_type&
operator*() const throw()
{
_GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);
return *_M_ptr;
}
element_type*
operator->() const throw()
{
_GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);
return _M_ptr;
}
其它的成员函数没有什么好看的,完整代码如下:
完整源码
template<typename _Tp>
class auto_ptr
{
private:
_Tp* _M_ptr;
public:
typedef _Tp element_type;
explicit
auto_ptr(element_type* __p = 0) throw() : _M_ptr(__p) { }
auto_ptr(auto_ptr& __a) throw() : _M_ptr(__a.release()) { }
template<typename _Tp1>
auto_ptr(auto_ptr<_Tp1>& __a) throw() : _M_ptr(__a.release()) { }
auto_ptr&
operator=(auto_ptr& __a) throw()
{
reset(__a.release());
return *this;
}
template<typename _Tp1>
auto_ptr&
operator=(auto_ptr<_Tp1>& __a) throw()
{
reset(__a.release());
return *this;
}
~auto_ptr() { delete _M_ptr; }
element_type&
operator*() const throw()
{
_GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);
return *_M_ptr;
}
element_type*
operator->() const throw()
{
_GLIBCXX_DEBUG_ASSERT(_M_ptr != 0);
return _M_ptr;
}
element_type*
get() const throw() { return _M_ptr; }
element_type*
release() throw()
{
element_type* __tmp = _M_ptr;
_M_ptr = 0;
return __tmp;
}
void
reset(element_type* __p = 0) throw()
{
if (__p != _M_ptr)
{
delete _M_ptr;
_M_ptr = __p;
}
}
auto_ptr(auto_ptr_ref<element_type> __ref) throw()
: _M_ptr(__ref._M_ptr) { }
auto_ptr&
operator=(auto_ptr_ref<element_type> __ref) throw()
{
if (__ref._M_ptr != this->get())
{
delete _M_ptr;
_M_ptr = __ref._M_ptr;
}
return *this;
}
template<typename _Tp1>
operator auto_ptr_ref<_Tp1>() throw()
{ return auto_ptr_ref<_Tp1>(this->release()); }
template<typename _Tp1>
operator auto_ptr<_Tp1>() throw()
{ return auto_ptr<_Tp1>(this->release()); }
} _GLIBCXX_DEPRECATED;
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 541. shared_ptr template assignment and void
template<>
class auto_ptr<void>
{
public:
typedef void element_type;
} _GLIBCXX_DEPRECATED;