auto_ptr源码解析

C++ STL的auto_ptr实现(位于memory头文件中)如下:

// TEMPLATE CLASS auto_ptr
template<class _Ty>
class auto_ptr;
//auto_ptr的proxy类,因为auto_ptr本身的copy构造和赋值函数不支持const引用参数(右值的类型),特定义此类为const引用代理
//在auto_ptr中添加参数类型为auto_ptr_ref<_Ty>的copy构造和赋值函数,同时添加proxy类-〉auto_ptr的隐式类型转换函数和构造函数
//对于右值copy,编译器的动作为:rvalue auto_ptr --> auto_ptr_ref --> 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 _Ty element_type;
//constructor使用explicit防止编译器隐式类型转换,(default)构造函数保证内部指针指向有效地址或0
// _THROW0(): #define _THROW0() throw () 异常规格说明保证此函数不抛出任何异常,否则系统就抛出unexpected ex然后terminate()
explicit auto_ptr(_Ty *_Ptr = 0) _THROW0()
: _Myptr(_Ptr)
{ // construct from object pointer
}
//copy constructor 1.是指针传递不是deep copy和指针copy,即指针所指对象的所有权传递到新构造的auto_ptr<T>对象,原auto_ptr<T>release指针对象的所有权,所以参数不能为const(要修改),所以要小心使用调用copy constructor的地方:函数参数传值(可能造成对象所有权传递到临时对象中)和返回对象!!!
//2.实现不能为指针copy:因为auto_ptr对象析构会自动delete raw 指针,指针copy会导致double delete
//3.实现不能为deep copy,因为参数是指针,你不知道指针具体所指的类型(多态)无法调用正确的new函数,也许你说你可以使用RTTI,但是你能保证指针所指的类型有virtual table([0]一般用于存放type_info)吗,另外还有C++从c那继承来的强类型。。。 另外还有效率问题。。。
auto_ptr(auto_ptr<_Ty>& _Right) _THROW0()
: _Myptr(_Right.release())
{ // construct by assuming pointer from _Right auto_ptr
}
//以auto_ptr_ref代理const引用参数的copy构造函数
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
}
//隐式类型转换函数模板,若_Other*可转换为_Ty*则此函数模板实例化后可编译通过,auto_ptr<_Ty>可转换为auto_ptr<_Other>
template<class _Other>
operator auto_ptr<_Other>() _THROW0()
{ // convert to compatible auto_ptr
return (auto_ptr<_Other>(*this));
}
//proxy类-〉auto_ptr的隐式类型转换函数
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);
}
// 同隐式类型转换函数模版的以autoptr<_Other>作为参数值的赋值和copy constructor
template<class _Other>
auto_ptr<_Ty>& 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
}
//适用于copy constructor的条款同样适用于copy assignment,另外注意两者的区别:后者的对象已构造好,所以
//1. 应该检查是不是“自己=自己” 2. 为支持连=返回(*this) 3.在重新赋值之前释放原有的资源 4.如果赋值有可能失败,要保证原有值不能被破坏
//这里仍然是巧妙的指针传递,检测1在reset中
auto_ptr<_Ty>& operator=(auto_ptr<_Ty>& _Right) _THROW0()
{ // assign compatible _Right (assume pointer)
reset(_Right.release());
return (*this);
}
//以auto_ptr_ref代理const引用参数的copy赋值函数
auto_ptr<_Ty>& 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);
}
//析构函数对自动调用delete,如果外面有其他pointer也指向相同的对象,那小心不要double delete,同时也不要写出两个auto_ptr指向同一个堆对象,如果有必要那用reference couting吧
~auto_ptr()
{ // destroy the object
//析构函数为什么不直接使用delete(因为在c++标准中delete空指针是安全的)?
if (_Myptr != 0)
delete _Myptr;
}
//dereference函数 1.为什么返回引用而不是T对象?
//因为指针和引用都支持多态,而返回对象会调用static type的copy constructor,有可能出现slice(如派生类->基类)
//2.记得检测空指针,dereference空指针会很恐怖:(
//3.加const为保证const auto_ptr<T>对象的调用,不能修改指针,但可以修改指针所指的值
_Ty& operator*() const _THROW0()
{ // return designated value
#if _HAS_ITERATOR_DEBUGGING
if (_Myptr == 0)
_DEBUG_ERROR("auto_ptr not dereferencable");
#endif /* _HAS_ITERATOR_DEBUGGING */
__analysis_assume(_Myptr);
return (*get());
}
//operator->类似于operator*(),但是注意operator->返回的结果要使用member-selection operator(->),所以返回dumb pointer或另一个auto_ptr
_Ty *operator->() const _THROW0()
{ // return pointer to class object
#if _HAS_ITERATOR_DEBUGGING
if (_Myptr == 0)
_DEBUG_ERROR("auto_ptr not dereferencable");
#endif /* _HAS_ITERATOR_DEBUGGING */
return (get());
}
//get获取dumb pointer
_Ty *get() const _THROW0()
{ // return wrapped pointer
return (_Myptr);
}
//release释放并返回dumb pointer,则返回的pointer不在此auto_ptr内释放,外部delete或其他auto_ptr自动释放
_Ty *release() _THROW0()
{ // return wrapped pointer and give up ownership
_Ty *_Tmp = _Myptr;
_Myptr = 0;
return (_Tmp);
}
//reset先释放原有的再和新的pointer关联
void reset(_Ty* _Ptr = 0)
{ // destroy designated object and store new pointer
if (_Ptr != _Myptr && _Myptr != 0)
delete _Myptr;
_Myptr = _Ptr;
}
private:
//dumb pointer
_Ty *_Myptr; // the wrapped object pointer
};
  • auto_ptr是什么?为什么要用它?
    smart pointer,防止memory leak和便于程序员编程时的内存管理
  • auto_ptr的典型应用case?
    取代局部指针变量
    类的指针成员变量
    (待续。。)
  • 用auto_ptr需要引用的头文件:

#include<memory>
std::auto_ptr<T> ptr(T*)

  • auto_ptr和dump pointer的区别?

auto_ptr析构时自动释放所指对象,但是它是对象不是T*,所以:
auto_ptr<T> ptr;
1.不能使用if( ptr ) / if( ptr == 0 ) / if( !ptr )判断是否空指针
2.不能传给int fun(T*);作为参数,但是可以将auto_ptr<T>转为T*,或这样调用 fun( &*ptr )。

  • 为什么防止编译器隐式转换auto_ptr为dump pointer?

auto_ptr<T> ptr;
隐式类型转换还是少用为好,它会隐藏很多bug,比如本错误的语句delete ptr也是合法的,另外complier的一次隐式类型转换只能调用一次用户自定义的类型转换函数

摘自:http://hi.baidu.com/kellyfu_ying/blog/category/c%2Cc%2B%2B

你可能感兴趣的:(object,delete,iterator,reference,Constructor,debugging)