gxx_base(二) 智能指针
为什么要使用智能指针?
在很多时候,为了提高程序的运行速度,经常需要引用同一内存块,可能多处都用到这一块内存,但不知道什么时候该释放,因此引入智能指针,对内存进行引用计数管理。
当有引用时,引用计数自增,当引用结束时,引用计数自减, 引用计数变为0时,释放指针指向的内存。
在 上一章中介绍了 GxxObject类, 它提供了 retain,release方法来增加引用计数和减小引用计数,直接用这个2个方法,会导致代码很难维护, 容易用错或者忘记调用它们,导致出现野指针或内存泄露问题。使用智能指针来维护引用计数,会让这个工作变得很简单。
众所周知,局部对象生命周期结束时,编译器会自动调用局部对象的析构函数,利用这个特性, 智能指针对象在构造时调用retain,在析构时调用release。
在下面这段代码中查看注释,更能容易理解智能指针的工作原理
template<class _Ty>
class GxxAutoPtr
{
public:
typedef _Ty element_type;
/*explicit*/ GxxAutoPtr(_Ty* _Ptr = 0)
: _Myptr(_Ptr)
{
// 在构造函数中调用 retain
if (_Ptr) _Myptr->retain();
}
GxxAutoPtr(const GxxAutoPtr<_Ty>& _Right)
{
// 在拷贝构造函数中也调用 retain
if (_Myptr == _Right.get()){
if (_Myptr) _Myptr->retain();
}else{
_Myptr = _Right.get();
if (_Myptr) _Myptr->retain();
}
}
template<class _Other>
GxxAutoPtr(GxxAutoPtr<_Other>& _Right)
{
// 在拷贝构造函数中也调用 retain
if (_Myptr == _Right.get()){
if (_Myptr) _Myptr->retain();
}else{
_Myptr = _Right.get();
if (_Myptr) _Myptr->retain();
}
}
~GxxAutoPtr()
{
// 在析构函数中调用release
if (_Myptr) _Myptr->release();
}
_Ty& operator*() const
{ // 重载* 操作符,用起来感觉像直接使用指针的*操作符一样
return (*_Myptr);
}
_Ty *operator->() const
{ // 重载->操作符, 用起来感觉像直接使用指针的->操作符一样
return (&**this);
}
_Ty* get() const
{
return _Myptr;
}
template<class _Other>
operator GxxAutoPtr<_Other>()
{
return (GxxAutoPtr<_Other>(*this));
}
operator _Ty* () const
{
// 将智能指针对象隐式的转为换为指针
return _Myptr;
}
GxxAutoPtr<_Ty>& operator = (_Ty* _Ptr)
{
// 重载=操作符,使得指针可以直接赋值给智能指针对象
// 两个指针相同,引用计数无需变化,什么也不做
if (_Myptr == _Ptr)
return *this;
// 将旧的指针对象的引用计数减少,因为本智能指针对象不再用它了
if (_Myptr) _Myptr->release();
_Myptr = _Ptr;
// 本智能指针引用新的指针对象了, 既然用了,引用计数也当然要跟着增加
if (_Myptr) _Myptr->retain();
return *this;
}
GxxAutoPtr<_Ty>& operator = (GxxAutoPtr<_Ty>& _Right)
{
// 重载=操作符,使得智能指针对象之间也可以赋值
if (_Myptr == _Right.get())
return *this;
if (_Myptr) _Myptr->release();
_Myptr = _Right.get();
if (_Myptr) _Myptr->retain();
return *this;
}
private:
_Ty* _Myptr;
};
下面举例实例化这个智能指针模板类:
class A : public GxxObject
{
GXX_CREATE_FUNC(A);
public:
int a, b;
};
typedef GxxAutoPtr<A> APtr;
void Func(APtr tmpPtr)
{
tmpPtr->a *= 10;
tmpPtr->b *= 10;
}
void main()
{
APtr p1 = A::create();
p1->a = 10;
p1->b = 12;
printf("%d,%d\n", p1->a, p1->b); // 输出 10,12
APtr p2 = p1;
printf("%d,%d\n", p2->a, p2->b); // 输出 10,12
Func(p2);
printf("%d,%d\n", p1->a, p1->b); // 输出 100,120
}