智能指针(smart pointer)是一个c++中必须去探讨的一个重点知识,它代理了原有的“裸指针”的一些行为,并添加了很多特性。
auto_ptr是为了解决资源泄漏的问题提供的一个智能指针类模板(注意:这只是一种简单的智能指针且很不完善,不推荐使用)
先用例子说明下
int main ()
{
auto ptr< class_need_resource > p1(new class_ need_resource);
auto_ptr<demo_class> p2(factory.create());
...
}
/*离开作用域,pl、P2 自动析构从而释放内存等资源
auto_ptr的构造函数接受new操作符或者对象工厂创建出的对象指针作为参数,
从而代理了原始指针。虽然它是一个对象,但因为重载了operator*和opreator->,
其行为非常类似指针,可以把它用在大多数普通指针可用的地方。当退出作用域时(离开函数main() 或者发生
异常),C++语言会保证auto_ptr对象销毁,调用auto_ptr的析构函数,进而使用delete
操作符删除原始指针释放资源*/
auto_ptr的实现原理:它是对原有裸指针进行包装后形成的一个类,并在类的析构函数中实现对指针所指空间的释放(delete),从而避免了因为程序员的大意而缺少的空间释放,而解决c/c++中饱受诟病的内存泄漏问题,因为类的析构是自动调用的。
比如,如果该类有2个成员变量,指向两个资源,在构造函数中申请资源A成功,但申请资源B失败,则构造函数失败,那么析构函数不会被调用,那么资源A则泄漏。
我们可以利用auto_ptr取代普通指针作为成员变量,这样首先调用成功的成员变量的构造函数肯定会调用其析构函数,那么就可以避免资源泄漏问题。
源代码的解析
//下面便是auto_ptr智能指针类模板的定义
template<class _Ty>
class auto_ptr {
public:
typedef _Ty element_type; //简单的类型的替换,更方便阅读
explicit auto_ptr(_Ty *_P = 0) _THROWO() //explicit关键字避免隐式转换,构造函数传入原始指针进行包装构造成智能指针对象
:_Owns(_P != 0),_Ptr(_P) {}
auto_ptr (const auto_ptr<_Ty>& _Y) _THROWO() //拷贝构造函数
:_Owns(_Y._Owns),_Ptr(_Y.release()) {}
auto_ptr<_Ty>& operator=(const auto_ptr<_Ty>& _Y) _THROWO() //重载=运算符,此函数很严谨,值得学习
{if (this != &_Y) //先判断是不是自己给自己赋值
{if (_Ptr != ._Y.get()) //判断两个智能指针对象是不是指向同一块内存
{if (_Owns) //判断=左值对象是否拥有空间所有权,拥有先释放本智能指针空间,再赋值
delete _Ptr;}
else if (_Y._Owns) //判断=的右值对象是否拥有所有权,有则将所有权授给=左值对象,即_Owns = true
_Owns = true;
_Ptr = _Y.Owns;}
return (*this);}
~auto_ptr() //析构函数,先判断是否拥有空间所有权,再释放或者直接返回
{if(_Owns)
delete_Ptr; }
_Ty& operator*()const _THROWO() //重载*运算符
{return (*get()); }
_Ty *operator->()const _THROWO()//重载->运算符,这都是让这个对象拥有原始指针同样的操作,而等价为指针;
{return (get());}
_Ty *get() const _THROWO
{return (_Ptr); }
_Ty *release() const _THROWO() //释放拥有权,_Owns = false
{((auto_ptr<_Ty> *)this)->_Owns = false;
return (Ptr); }
private :
bool _Owns; //1代表拥有空间所有权,0则相反
_Ty *_Ptr; //所封装的原始指针
J;
auto_ptr十分不完善,也存在很多漏洞,一般不使用:
例如:
/*智能指针管理多个对象的问题*/
void test2(){
auto_ptr<A> pa(new A[3]);//核心转存,解映射出错
/*为什么智能指针不能管理对象数组*/
}
一次分配多个对象我们必须要用delete[]去释放,不然会出错。最终的问题其实就是delete和delete[]的区别问题。delete用于释放单个对象,获取的是对象的地址,并且调用free,而对象数组的分配有所不同,除了分配所需要大小的堆内存空间外,这段堆内存的开头还分配了4个字节的空间,用于存放分配对象的个数,在释放的时候必须把最开头的四个字节包含进去,delete[]在释放的时候,将得到的地址减4,这样取得了最开始的地址,这样的释放才是正确的释放,而delete的释放并没有减4的操作,所以无法正确的释放 。`
又比方说:auto_ptr虽和其它智能指针同样,只保留一个对象所有权,但这样简单粗暴不合逻辑的所有权转接是不实际的。
值得说明的是在c++2011中出现的smart_ptr指针,真正做到了“智能”,其不仅可以管理对象数组,还具有指针的拷贝语义,在管理对象数组上smart_ptr采用了特化的处理,而在处理拷贝语义上采用了设置计数器这里不做详细说明。当然还有许多更好的scoped_ptr,scoped_array,shared_ptr,shared_array,weak_ptr等后续我们会继续剖析他们。