您的位置:首页 > 其它

auto_ptr源码解析

2012-08-01 10:35 295 查看

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: