您的位置:首页 > 其它

引用计数的智能指针的实现

2014-09-01 19:34 519 查看
引用计数的智能指针是对《Effective C++ 条款13:以对象管理资源》的一个实现。

我们要设计一个智能指针,使他能够管理资源,在正确的实际调用资源的析构函数。

首先我们需要一个指针reference来指向资源,当智能指针构造时,用reference指针指向资源,在我们确定资源应该被析构时,我们对reference指针进行delete。

如果只有reference指针的话,只能实现出auto_ptr的效果,我们还需要添加引用计数系统counter来统计指向资源的智能指针的个数。counter不可以是一个普通的int型变量,因为不同的智能指针可能会有相同的计数,也不可以是一个static变量,因为同时存在的智能指针可以指向不同的资源,也就拥有不同的引用计数。因此将counter设计成一个指向int的指针,指向相同资源的智能指针的counter也指向相同的int值,这样对counter做修改时,就会影响到所有拥有这个counter的智能指针。

我们的智能指针还应该能实现多态的效果,因此指向同一个资源的智能指针中的reference指针可能有不同的类型。然而这就给我们的析构过程带来了困扰,我们在析构资源的时候需要知道资源原始的类型与指针,因此我们用一个指向void*的指针originalReference来保存原始的指针。

有了指向原始资源的指针,我们还需要原始资源的类型才能正常delete,我们在每个资源创建出来时,提供一个指向特殊的销毁函数的指针originalDestructor,保证这个函数能够成功的销毁资源。

有了这些成员变量我们就可以实现出一个简单的引用计数的智能指针。可见智能指针占用的空间要比普通指针大数倍。

按照《条款14:在资源管理类中小心copying行为》,仔细的为智能指针添加copying行为。

最后适当的重载操作符,使智能指针能够像一个普通指针那样使用。

namespace cylib {

// 引用计数操作器
template<typename T> struct ReferenceCounterOperator
{
// 返回一个引用计数器
static int* CreateCounter(T* reference)
{
return new int(0);

}
// 删除引用函数
static void DeleteReference(int* counter, void* reference)
{
delete counter;// 删除计数器
delete (T*)reference;// 删除资源
}
};

// 智能指针类
template<typename T> class SmartPtr
{
private:
template<typename X> friend class SmartPtr;
// 删除器
typedef void (*Destructor)(int*, void*);
// 引用计数器
int* counter;
// 引用资源,在拷贝过程中可能改变类型
T* reference;
// 原始引用资源,保持资源第一次创建时的指针
void* originalReference;
// 原始资源删除函数,在最后一个引用被析构时调用,删除资源
Destructor originalDestructor;

// 增加引用计数
void Inc()
{
if (counter)
{
++(*counter);
}
}
// 减少引用计数,如果资源不再被引用则删除资源
void Dec()
{
if (counter)
{
if (--(*counter) == 0)
{
originalDestructor(counter, originalReference);
counter = 0;
reference = 0;
originalReference = 0;
originalDestructor = 0;
}
}
}

// 返回当前计数器
int* Counter() const
{
return counter;
}

// 私有构造器
SmartPtr(int* _counter, T* _reference, void* _originalReference, Destructor _originalDestructor)
: counter(_counter)
, reference(_reference)
, originalReference(_originalReference)
, originalDestructor(_originalDestructor)
{
Inc();
}

public:
// 获取资源的直接指针
T* get() const
{
return reference;
}
// 重载->操作符
T* operator->()const
{
return reference;
}
// 重载*操作符,危险!
T& operator*() const {
return *reference;
}

// 构造一个空的智能指针,不指向任何资源
SmartPtr()
: counter(0)
, reference(0)
, originalReference(0)
, originalDestructor(0)
{}
// 用一个普通指针构造智能指针,是最基本的用法
SmartPtr(T* pointer)
: counter(0)
, reference(0)
, originalReference(0)
, originalDestructor(0)
{
if (pointer)
{
counter = ReferenceCounterOperator<T>::CreateCounter(pointer);// 创建新的计数器
reference = pointer;// 获取当前资源的引用
originalReference = pointer;// 将原始资源置为当前资源
originalDestructor = ReferenceCounterOperator<T>::DeleteReference;// 连接删除器
Inc();// 引用计数增加
}
};
// 用另一个同类型的智能指针进行拷贝构造,不创建新资源
SmartPtr(const SmartPtr<T>& pointer)
: counter(pointer.counter)
, reference(pointer.reference)
, originalReference(pointer.originalReference)
, originalDestructor(pointer.originalDestructor)
{
Inc();// 引用计数增加
}
// 用其他类型的智能指针进行转型拷贝构造,不创建新资源
// 将原始类型U转换为当前智能指针的类型T,但是原始资源与原始删除器不变
template<typename U> SmartPtr(const SmartPtr<U>& pointer)
: counter(0)
, reference(0)
, originalReference(0)
, originalDestructor(0)
{
T* converted = pointer.get();
if (converted)
{
counter = pointer.Counter();
reference = converted;
originalReference = pointer.originalReference;
originalDestructor = pointer.originalDestructor;
Inc();
}
}

// 析构当前的智能指针,减少引用计数
~SmartPtr()
{
Dec();
}

// 将一个普通指针的值赋给智能指针
// 智能指针之前引用的资源取消,由普通指针构造出新的智能指针
// 构造失败则将智能指针置为空
SmartPtr<T>& operator=(T* pointer)
{
Dec();// 原本的资源引用减少
if (pointer)
{
counter = ReferenceCounterOperator<T>::CreateCounter(pointer);
reference = pointer;
originalReference = pointer;
originalDestructor = &ReferenceCounterOperator<T>::DeleteReference;
Inc();
}
else
{
counter = 0;
reference = 0;
originalReference = 0;
originalDestructor = 0;
}
return *this;
}
// 将另一个智能指针的值赋给自身
// 智能指针之前引用的资源取消,并引用新的智能指针的资源
SmartPtr<T>& operator=(const SmartPtr<T>& pointer)
{
if (this != &pointer)// 判断是否自赋值
{
Dec();
counter = pointer.counter;
reference = pointer.reference;
originalReference = pointer.originalReference;
originalDestructor = pointer.originalDestructor;
Inc();
}
return *this;
}
// 将一个不同类型的智能指针赋给自身
// 智能指针之前引用的资源取消,并引用新的智能指针的资源
// 转型失败的话返回空智能指针
template<typename U> SmartPtr<T>& operator=(const SmartPtr<U>& pointer)
{
T* converted = pointer.get();
Dec();
if (converted)
{
counter = pointer.counter;
reference = converted;
originalReference = pointer.originalReference;
originalDestructor = pointer.originalDestructor;
Inc();
}
else
{
counter = 0;
reference = 0;
originalReference = 0;
originalDestructor = 0;
}
return *this;
}

// 重载比较操作符,用于比较智能指针与普通指针是否指向相同资源
bool operator==(const T* pointer)const { return reference == pointer; }
bool operator!=(const T* pointer)const { return reference != pointer; }
bool operator>(const T* pointer)const { return reference>pointer; }
bool operator>=(const T* pointer)const { return reference >= pointer; }
bool operator<(const T* pointer)const { return reference<pointer; }
bool operator<=(const T* pointer)const { return reference <= pointer; }

// 重载比较操作符,用于比较两个智能指针是否指向相同资源
bool operator==(const SmartPtr<T>& pointer)const { return reference == pointer.reference; }
bool operator!=(const SmartPtr<T>& pointer)const { return reference != pointer.reference; }
bool operator>(const SmartPtr<T>& pointer)const { return reference>pointer.reference; }
bool operator>=(const SmartPtr<T>& pointer)const { return reference >= pointer.reference; }
bool operator<(const SmartPtr<T>& pointer)const { return reference<pointer.reference; }
bool operator<=(const SmartPtr<T>& pointer)const { return reference <= pointer.reference; }

// 智能指针指向非空时有true的布尔值
operator bool()const{ return reference != 0; }

};

}


测试代码:

#include <iostream>
#include "SmartPoint.h"
using namespace std;

class B {
public:
B() { cout << "构造了一个基类~" << endl; }
virtual ~B() { cout << "基类被析构啦!" << endl; }
virtual void message() { cout << "基基基基基基基基基基基基" << endl; }
};

class D : public B {
public:
D() { cout << "构造了一个派生类~" << endl; }
virtual ~D() { cout << "派生类被析构啦!" << endl; }
virtual void message() { cout << "派派派派派派派派派派派派" << endl; }
};

void test1() {
cout << "构造演示:" << endl;
cylib::SmartPtr<B> bp = new B();
cylib::SmartPtr<B> bp2(new B());
}
void test2() {
cout << "比较演示:" << endl;
cylib::SmartPtr<B> bp = new B();
B* p = bp.get();
cylib::SmartPtr<B> bp2 = bp;
if (bp == p) cout << "相等" << endl;
if (bp == bp2) cout << "相等" << endl;
}
void test3() {
cout << "多态演示:" << endl;
cylib::SmartPtr<B> bp;
cylib::SmartPtr<D> dp = new D();
bp = dp;
bp->message();
}

int main()
{
cout << "---------------" << endl;
test1();
cout << "---------------" << endl;
test2();
cout << "---------------" << endl;
test3();
cout << "---------------" << endl;
system("pause");

}


测试结果:

---------------
构造演示:
构造了一个基类~
构造了一个基类~
基类被析构啦!
基类被析构啦!
---------------
比较演示:
构造了一个基类~
相等
相等
基类被析构啦!
---------------
多态演示:
构造了一个基类~
构造了一个派生类~
派派派派派派派派派派派派
派生类被析构啦!
基类被析构啦!
---------------
请按任意键继续. . .
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: