auto_ptr是常用的智能指针,其实现很简单,源代码也很短,但是中间有个代理类auto_ptr_ref用的很巧妙,值得学习。
/* * Copyright (c) 1997-1999 * Silicon Graphics Computer Systems, Inc. * * Copyright (c) 1999 * Boris Fomitchev * * This material is provided "as is", with absolutely no warranty expressed * or implied. Any use is at your own risk. * * Permission to use or copy this software for any purpose is hereby granted * without fee, provided the above notices are retained on all copies. * Permission to modify the code and to distribute modified code is granted, * provided the above notices are retained, and a notice that the code was * modified is included with the above copyright notice. * */ #ifndef _STLP_AUTO_PTR_H #define _STLP_AUTO_PTR_H _STLP_BEGIN_NAMESPACE // implementation primitive //auto_ptr基类,声明指针和指针初始化操作 class __ptr_base { public: void* _M_p; void __set(const volatile void* p) { _M_p = __CONST_CAST(void*,p); } void __set(void* p) { _M_p = p; } }; //使用auto_ptr_ref,在源代码后面举例说明 template <class _Tp> class auto_ptr_ref { public: __ptr_base& _M_r; _Tp* const _M_p; //_M_r是引用,_M_p是常量指针,在构造函数初始化列表初始化 auto_ptr_ref(__ptr_base& __r, _Tp* __p) : _M_r(__r), _M_p(__p) { } //释放,把基类_M_r指针设为空 _Tp* release() const { _M_r.__set(__STATIC_CAST(void*, 0)); return _M_p; } private: //explicitely defined as private to avoid warnings: //显示定义,避免警告。 //重载“=”为私有函数,不允许调用 typedef auto_ptr_ref<_Tp> _Self; _Self& operator = (_Self const&); }; template<class _Tp> class auto_ptr : public __ptr_base { public: typedef _Tp element_type; typedef auto_ptr<_Tp> _Self; _Tp* release() _STLP_NOTHROW { _Tp* __px = this->get(); this->_M_p = 0; return __px; } void reset(_Tp* __px = 0) _STLP_NOTHROW { _Tp* __pt = this->get(); if (__px != __pt) delete __pt; this->__set(__px); } _Tp* get() const _STLP_NOTHROW #if !defined (__GNUC__) || (__GNUC__ > 2) //像C语言一样,用static_cast<> { return __STATIC_CAST(_Tp*, _M_p); } #else //像C++一样用reinterpret { return __REINTERPRET_CAST(_Tp*, _M_p); } #endif #if !defined (_STLP_NO_ARROW_OPERATOR) //返回指针 _Tp* operator->() const _STLP_NOTHROW { //断言,确保返回指针不是空指针 _STLP_VERBOSE_ASSERT(get() != 0, _StlMsg_AUTO_PTR_NULL) return get(); } #endif //返回引用 _Tp& operator*() const _STLP_NOTHROW { //断言,确保指针不是空指针,这样才可以解引用 _STLP_VERBOSE_ASSERT(get() != 0, _StlMsg_AUTO_PTR_NULL) return *get(); } //显示构造函数,不允许隐式调用 explicit auto_ptr(_Tp* __px = 0) _STLP_NOTHROW { this->__set(__px); } /* 复制构造函数,需要注意的是复制构造函数是auto_ptr传递的是指针的所有权。 因为要修改传入参数的所有权,所以传入参数不是const(不同于其他复制构造函数) auto_ptr<int>p1(new int(10)); auto_ptr<int>p2(p1); p2指向new int(10)后,p1就成了空指针,他们不能共享所有权,因此auto_ptr不能作为 容器元素,因为容器元素要支持拷贝和复制 */ #if defined (_STLP_MEMBER_TEMPLATES) # if !defined (_STLP_NO_TEMPLATE_CONVERSIONS) template<class _Tp1> auto_ptr(auto_ptr<_Tp1>& __r) _STLP_NOTHROW { _Tp* __conversionCheck = __r.release(); this->__set(__conversionCheck); } # endif template<class _Tp1> auto_ptr<_Tp>& operator=(auto_ptr<_Tp1>& __r) _STLP_NOTHROW { _Tp* __conversionCheck = __r.release(); reset(__conversionCheck); return *this; } #endif //同类型auto_ptr作为复制构造函数参数,不用模板 auto_ptr(_Self& __r) _STLP_NOTHROW { this->__set(__r.release()); } //赋值操作符和复制构造函数类型,传递的是所有权,不是值传递 _Self& operator=(_Self& __r) _STLP_NOTHROW { reset(__r.release()); return *this; } //析构函数很简单,只是调用指针指向对象的析构函数,释放指针指向的空间 //delete而不是delete[],所以auto_ptr不能指向数组 ~auto_ptr() _STLP_NOTHROW { /* boris : reset(0) might be better */ delete this->get(); } //使用auto_ptr_ref,在源代码后面举例说明 auto_ptr(auto_ptr_ref<_Tp> __r) _STLP_NOTHROW { this->__set(__r.release()); } _Self& operator=(auto_ptr_ref<_Tp> __r) _STLP_NOTHROW { reset(__r.release()); return *this; } #if defined(_STLP_MEMBER_TEMPLATES) && !defined(_STLP_NO_TEMPLATE_CONVERSIONS) template<class _Tp1> operator auto_ptr_ref<_Tp1>() _STLP_NOTHROW { return auto_ptr_ref<_Tp1>(*this, this->get()); } template<class _Tp1> operator auto_ptr<_Tp1>() _STLP_NOTHROW { return auto_ptr<_Tp1>(release()); } #else operator auto_ptr_ref<_Tp>() _STLP_NOTHROW { return auto_ptr_ref<_Tp>(*this, this->get()); } #endif }; _STLP_END_NAMESPACE #endif /* _STLP_AUTO_PTR_H */ // Local Variables: // mode:C++ // End:
auto_ptr是智能指针。在赋值(复制构造函数或赋值操作符)的时候是传递指针所用权,而不是传递值。所以在复制构造函数或复制操作符函数要取消原来指针的所有权,因此就不能把传入的参数声明为const类型。但是有些情况下,必须要声明为const类型,例如
auto_ptr<int> p(auto_ptr<int>(new int(10));
使用临时对象时,必须用const修饰
auto_ptr(auto_prt<int> const&),而auto_ptr要修改原来指针的所有权,声明成了auto_ptr(auto_prt<int> &),上面代码不能通过编译。
再例如
auto_ptr<int> p1(NULL);
p1=(auto_ptr<int>(new int(10));
有和上面一样的问题,临时对象是右值,非const&不能指向右值。
这样情况下就引入了auto_ptr_ref,auto_ptr可以隐式转换为auto_ptr_ref,这样上面的程序就不会出错。
时间: 2024-10-15 01:02:04