《STL源碼剖析》---_auto_ptr.h閱讀筆記
來源:程序員人生 發布時間:2014-10-08 22:55:01 閱讀次數:1921次
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,這樣上面的程序就不會出錯。
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈