智能指针
1、智能指针概念
由于C++中没有自动回收内存的机制,程序每次new出来的内存都要通过delete来回收,所以很容易会发生内存泄漏的问题。
引入智能指针可以有效的缓解回收内存方面的问题。
智能指针实际是存储指向动态分配对象指针的类,定义一个类来封装资源的分配和释放。
智能指针要求资源的有效期与持有资源的对象的生命期严格绑定,即由对象的构造函数完成资源的分配,同时由析构函数来完成资源的释放,在这种要求下,只要对象能够正确的析构,就不会出现资源泄漏的问题。
2、智能指针的实现
智能指针要求实现:
(1)构造、析构资源
(2)实现operator*和operator->的重载函数
(3)解决拷贝构造函数和赋值运算符重载带来的问题(浅拷贝带来的问题)
3、模拟实现几种智能指针(基本功能的实现)
解决方法1:AutoPtr (实质是管理权的转移)
template
class AutoPtr
{
public:
AutoPtr(T* ptr)
:_ptr(ptr)
{}
~AutoPtr()
{
if (_ptr)
{
delete _ptr;
_ptr = NULL;
}
}
T& operator*()
{
return *_ptr;
}
T*operator->()
{
return _ptr;
}
AutoPtr(AutoPtr& ap)
{
//转移管理权
_ptr = ap._ptr;
ap._ptr = NULL;
}
AutoPtr& operator = (AutoPtr& ap)
{
delete _ptr;
_ptr = ap._ptr;
ap._ptr = NULL;
return *this;
}
void display()
{
cout << *_ptr << endl;
}
protected:
T* _ptr;
};
void TestAutoPtr()
{
AutoPtr ap1(new int(10));
AutoPtr ap2 = ap1;
AutoPtr ap3(new int(20));
ap3 = ap2;
}
这种方法的缺陷是会使之前的指针变为野指针,不符合我们的预期。
解决方法2:ScopedPtr (防拷贝)
将拷贝构造函数和赋值运算符重载函数访问限定符设置为protected或private,只声明不定义,并且避免别人在类外定义
template
class ScopedPtr
{
public:
ScopedPtr()
{}
~ScopedPtr()
{
if (_ptr)
{
delete _ptr;
_ptr = NULL;
}
}
T& operator*()
{
return *_ptr;
}
T*operator->()
{
return _ptr;
}
protected:
ScopedPtr(ScopedPtr& s);
ScopedPtr operator=(ScopedPtr& s);
protected:
T* _ptr;
};
void TestScopedPtr()
{
ScopedPtr sp1;
ScopedPtr sp2(sp1);
}
这种方法的缺陷是有功能缺失。
解决方法3:SharedPtr (采用引用计数)
template
class SharedPtr
{
public:
SharedPtr(T* ptr)
:_ptr(ptr)
, _refCount(new int(1))
{}
~SharedPtr()
{
Release();
}
T& operator*()
{
return *_ptr;
}
T*operator->()
{
return _ptr;
}
inline void Release()
{
if (--*_refCount == 0)
{
cout << "delete" << endl;
delete _refCount;
}
}
SharedPtr(const SharedPtr& sp)
:_ptr(sp._ptr)
, _refCount(sp._refCount)
{
(*_refCount)++;
}
SharedPtr& operator=(const SharedPtr& sp)
{
if (_ptr != sp._ptr)
{
Release();
_ptr = sp._ptr;
_refCount = sp._refCount;
(*_refCount)++;
}
return *this;
}
protected:
T* _ptr;
int* _refCount;
};
void TestSharedPtr2()
{
SharedPtrap1(new int(10));
SharedPtr ap2(ap1);
SharedPtr ap3(new int(20));
ap2 = ap3;
}
这种方法的缺点是代码复杂,并且会引起循环引用。
这里模拟实现了三种智能指针,它们各有优缺点,大家可以根据应用情况选择使用。