auto_ptr 是一個輕量級的智能指針, 定義於 memory (非memory.h)中, 命名空間為 std.
auto_ptr 適合用來管理生命周期比較短或者不會被遠距離傳遞的動態對象, 最好是局限於某個函數內部或者是某個類的內部.
使用方法:
std::auto_ptr<int> pt(new int(10));
pt.reset(new int(11));
3個重要的函數:
(1) get 獲得內部對象的指針, 由於已經重載了()方法, 因此和直接使用對象是一樣的.如 auto_ptr <int> sp(new int(1)); sp 與 sp.get()是等價的
(2) release 放棄內部對象的所有權,將內部指針置為空, 返回所內部對象的指針, 此指針需要手動釋放
std::auto_ptr<int> ap0(new int(1));
int* pa = ap0.release();
delete pa; // 需要手動釋放
(3) reset 銷毀內部對象並接受新的對象的所有權(如果使用缺省參數的話,也就是沒有任何對象的所有權)
其構造函數被聲明為 explicit, 因此不能使用賦值符對其賦值(即不能使用類似這樣的形式 auto_ptr<int> p = new int;)
(1) auto_ptr 的對象所有權是獨占性的.
auto_ptr 的拷貝構造和賦值操作符所接受的參數類型都是非const的引用類型(而一般都應該使用的const引用類型), 其原因在於為了使其內部能調用了 release 方法將原有的對象進行釋放, 然後使用新對象替換原有的對象.
因此導致動態對象的所有權被轉移了, 新的 auto_ptr 獨占了動態對象的所有權. 被拷貝對象在拷貝過程中被修改, 拷貝物與被拷貝物之間是非等價的.
下面的使用方法將會出錯:
std::auto_ptr<int> pt1(new int(10));
std::auto_ptr<int> pt2 = pt1;
printf("pt1:%d\n", pt1); // 此時應輸出 0
printf("pt1 value:%d\n", *pt1); // 錯誤, 對象已釋放
(2) 不能將 auto_ptr 放入到標准容器中. 標准庫容器無准備的拷貝行為, 會導致原 auto_ptr 內的對象被釋放, 造成難以發覺的錯誤.
(1) auto_ptr 不能指向數組
(2) auto_ptr 不能共享所有權
(3) auto_ptr 不能通過復制操作來初始化
(4) auto_ptr 不能放入容器中使用
(5) auto_ptr 不能作為容器的成員
(6) 不能把一個原生指針給兩個智能指針對象管理(對所有的智能指針).
int* p = new int;
auto_ptr<int> ap1(p);
auto_ptr<int> ap2(p); // 錯誤, p不能給第二個智能指針對象. 會引起兩次釋放p
VC中的源碼實現
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));
}
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
};