原创文章 转载请注明出处http://blog.csdn.net/effective_coder
欢迎来到内存这块雷区,在对内存分配器进一步讨论之前我觉得有必要先讨论一下STL中的auto_ptr,我也加了很多STL的讨论社区以及很多群,长久以来发现了一个很大的问题,太多的人反映出不敢用auto_ptr,原因是好多好多未定义行为,用到最后自己都摸不着头脑了,其实如果来分析一下他的来龙去脉,也不是那么难!为此我采取分析STL的auto_ptr和boost里面的shared_ptr两种不同风格的智能指针,希望更具全面性!(注:在0X标准中auto_ptr已经取消了,被更高级的指针替代,不过这里还是讨论一下)
在我另一篇文章中对auto_ptr有一些基本的介绍auto_ptr简介 对于怎么用智能指针 不属于本文范畴 看过那篇文章对于auto_ptr也应该了解了!
这里多说一些,在我们的程序中经常出现
ClassA *ptr=new ClassA;
```````````````````中间步骤`````````
Delete ptr;
这样的风格,中间步骤发生异常或者是忘记加delete,或者是delete之后忘记置0 ,造成内存泄露和使用错误,针对这个问题如何解决,在C++ primer上面为我们提供了了两种解决方案,
1:设置拥有权的转移
2:使用引用计数的方式
我记得大一的时候看到这两点,完全看不懂是什么意思,呵呵,现在终于可以一笑置之了!
所以针对这个两个解决方案,出现了两种风格的智能指针,STL中的auto_ptr属于拥有权转移指针,boost中的shared_ptr属于引用计数型(boost里面的智能指针有6个,这里只是其中一个)
针对auto_ptr:
对于设置拥有权限转移的指针,我们需要做的就是在复制和赋值的时候重定向指针,使得他们不会出现多个指针指向同一个对象,出现指针悬空的现象,在C++ primer 591页有一个针对auto_ptr的表格,列出了所有成员函数以及相应的说明,其实我觉得就算不懂STL源码,在C++ primer看到591页的情况下,写出这个模拟的auto_ptr不是什么难事,先看我的源码 :
template
class Auto_ptr
{
private:
Ty *ap;
public:
explicit Auto_ptr (Ty * ptr = 0)throw()
:ap(ptr)
{//构造函数,指定explicit不能隐式使用
}
Auto_ptr (Auto_ptr &r)throw()
:ap( r.release() )
{ //复制构造,注意看参数
}
template
Auto_ptr (Auto_ptr<_other> &other )throw()
:ap (other.release() )
{//重载的模版复制函数,作用稍后细说
}
Auto_ptr& operator= (Auto_ptr &other)throw()
{//赋值操作符,同样转移了拥有权
reset( other.release() );
return *this;
}
template
Auto_ptr& operator= (Auto_ptr &other)throw()
{//重载,同复制构造函数
reset( other.release() );
return *this;
}
//重置函数,带默认参数
void reset( Ty* ptr = 0 )throw(){
if( ptr != ap )
{
delete ap;
ap = ptr;
}
}
//该函数释放掉自己的对象,并返回
Ty* release ()throw(){
Ty* temp( ap );
ap = 0;
return temp;
}
//这个接口标准里面没有,是我自己加的,我觉得有必要转型
operator bool()throw(){
return ap;
}
~Auto_ptr()throw(){
//析构函数
delete ap;
}
Ty* get() const throw(){
return ap;
}
Ty& operator* ()throw(){
return *ap;
}
Ty* operator-> ()throw(){
return ap;
}
};
代码不多,也很好懂,这里我特别说明一下几点:
1:构造函数一定要加explicit关键字,因为auto_ptr只能显式的构造(参见auto_ptr标准)
2:复制构造函数的参数千万不能加const,因为加了const就成了锁定指针了,拥有权再也转移不出去了,何谈复制(同赋值操作符)
3:为什么要重载一个模版函数,难道指针之间可以互相复制或赋值吗?其实我们这里这样写主要是为了基类和派生类的转换,这样可以不影响多态性的发挥!
4:接下来的几个函数见名知意,很简单,而且我们的Auto_ptr没有++ --操作符,这个根据需要自己定制,当标准的智能指针不满足我们需要可以自己随便改啊(只要你喜欢)
5:这点很重要,现在这个类还不完整,没有const的功能,即锁定拥有权不转移的功能,为此参考了Greg Colvin的一份实例,他的做法有点高级过头了
template
struct ref_auto_ptr
{
T* p;
ref_auto_ptr(T *r = 0)throw()
:p(r){
//仅只有成员和构造
}
}
首先在我们的类之前添加这么一个类 然后在Auto_ptr中添加以下成员函数:
Auto_ptr(ref_auto_ptr &rh)throw()
:ap(rh.p)
{
}
Auto_ptr& operator =(ref_auto_ptr &rh)throw()
{
reset(rh.p);
return *this;
}
template
operator ref_auto_ptr ()throw()
{
return ref_auto_ptr( release() );
}
template
operator Auto_ptr ()throw()
{
return Auto_ptr( release() );
}
说实话我还不是很明白这个转型代码,就算明白点也感觉说不出来,他把右值转化为左值,这样子非const的可以转化,但是const就不能转化,这个怎么解释清楚点,希望留言指点!
到现在我们基本的Auto_ptr功能完备实现了,测试一下:
#include "auto_ptr.h"
int _tmain(int argc, _TCHAR* argv[])
{
Auto_ptr ptr( new int(1024) );
Auto_ptr ptr2;
ptr2 = ptr;
cout<< *ptr2 <<" "< ptr3( new int(1024) );
Auto_ptr ptr4;
ptr4 = ptr3; //编译期错误“没有找到接受“const Auto_ptr”类型的右操作数的运算符(或没有可接受的转换)”
system("pause");
return 0;
}
下一节 :定制智能指针 shared_ptr
求助:希望懂的人给我解释下,上面那个const转型是如何把右值转成了左值,谢谢!