上一篇讲了最多只能由一个指针标识堆空间的SmartPointer,本篇讲解另一种智能指针--SharedPointer。
设计要点:
使用类模板实现。
继承自Pointer类
通过计数机制(ref)标识堆空间:被指向时ref++;指向的指针被置空时ref--;当计数变量ref为0时堆空间应该被释放。所以计数变量和堆空间对象是绑定在一起。
由于SharedPointer支持多个对象同时指向一片堆空间,所以需要支持比较操作,所以需要实现比较操作符重载。
由于const对象会使用指针操作符,所以需要重载const版本的(->)和(*)操作符重载。
由于需要重载比较操作符,需要将Pointer类的get函数和isNull函数做成const成员函数。
SharedPointer类声明及完整实现:
template <typename T>
class SharedPointer : public Pointer<T>
{
protected:
int* m_ref;//计数变量
public:
SharedPointer(T* p = NULL) : m_ref(NULL)
{
if(p)
{
this->m_ref = static_cast<int*>(malloc(sizeof(int)));
if(this->m_ref)
{
(*this->m_ref) = 1;//申请空间成功后表示已经有指针指向它,计数变量加1。
this->m_pointer = p;
}
else//抛出异常
{
THROW_EXCEPTION(NoEnoughMemoryException,"No enough memory to create...");
}
}
}
SharedPointer(const SharedPointer<T>& obj):Pointer<T>(NULL)//拷贝构造,拷贝成功后计数变量加1
{
this->m_ref = obj.m_ref;
this->m_pointer = obj.m_pointer;
if(this->m_ref)
(*this->m_ref)++;
}
SharedPointer<T>& operator= (const SharedPointer<T>& obj)//赋值操作符重载,赋值成功后计数变量加1
{
if(this != &obj)
{
clear();//清理当前指向
this->m_pointer = obj.m_pointer;//重新赋值
this->m_ref = obj.m_ref;
(*this->m_ref)++;
}
return *this;
}
void clear()//清除当前对象指向的空间,当计数变量为0时释放堆空间和计数变量占用的空间
{
T* toDel = this->m_pointer;
int* ref = this->m_ref;//
this->m_pointer = NULL;
this->m_ref = NULL;//两步操作执行后计数变量数值不变。
if(ref)//清理指向堆空间的指针
{
( *ref)--;
if((*ref) == 0)
{
free(ref);
delete(toDel);
}
}
}
~SharedPointer()
{
clear();
}
};
//比较操作符重载,作为全局重载函数
template <typename T>
bool operator == (const SharedPointer<T>& l, const SharedPointer<T>& r)
{
return (l.get() == r.get());
}
template <typename T>
bool operator != (const SharedPointer<T>& l, const SharedPointer<T>& r)//const对象只能调用const成员函数
{
return !(l == r);
}
SharedPointer最大程度的模拟了原生指针的行为。
计数机制确保多个智能指针合法的指向同一片堆空间。
堆对象的生命周期由智能指针进行管理。
实现了自动管理内存。
使用军规:
只能用来指向堆空间中的单个变量或对象,不能是栈等内存。
不同类型的智能指针对象不能混合使用,SmartPointer对象和SharedPointer对象不能混合使用。
在使用智能指针后不要使用delete释放智能指针指向的堆空间。
测试代码:
class Test : public Object
{
public:
int value;
Test():value(0)
{
cout << "Test()" << endl;
}
Test(int value)
{
this->value = value;
cout << "Test()" << endl;
}
~Test()
{
cout << "~Test()" << endl;
}
};
int main()
{
SharedPointer<Test> sp = new Test();
SharedPointer<Test> nsp = NULL;
nsp = sp;
cout << sp->value << endl;
cout << nsp->value << endl;
nsp->value = 100;
cout << sp->value << endl;
cout << nsp->value << endl;
cout << (sp == nsp) << endl;
nsp.clear();
cout << (sp == nsp) << endl;
cout << endl;
const SharedPointer <Test> pp = new Test(111);
//(pp->value) = 100;//const对象不能修改成员变量的值,可以加上mutable强制破除只读属性。
cout << pp->value << endl;
输出结果:
Test()
0
0
100
100
1
0
Test()
111
~Test()
~Test()
请自行对照结果分析原因。
小结:
这两篇内容重新设计了智能指针,使得智能指针在使用中更安全和方便。