引用计数主要用于自动垃圾回收,C++程序直接运行于cpu,本身是没有垃圾回收功能的,但可以通过引用计数实现一个带半自动垃圾回收功能的类,之所以称之为半自动,典型的是因为它不像java/python那样能处理循环指针(引用)。从C++11,标准库里已经自带了使用引用计数的智能指针std::shared_ptr。
实现引用计数的核心原理是相同的数据对象指针和相同的引用计数器指针一起,当引用对象被创建或被拷贝时,引用计数要加1;当引用对象被销毁或被覆盖时,引用计数减1;当引用计数为0时,数据对象被销毁。细节上要注意的是当引用对象被覆盖时,当前引用计数要先减1。
对应于C++来说,实现引用计数的关键就是构造函数、拷贝构造函数、赋值。代码如下:
template <class T>
class Ref
{
T *ptr; // 数据对象指针
int *count; // 引用计数器指针
void dec()
{
if (count)
{
--(*count);
if (0 == *count)
{
// 引用计数为0则删除数据对象指针和引用计数器指针
delete ptr;
ptr = NULL;
delete count;
count = NULL;
}
}
}
void inc()
{
if (count)
++(*count);
}
public:
Ref() : ptr(NULL), count(NULL)
{
}
Ref(T *t) // 注意:这里不能传入栈内存指针,由调用方保证。
: ptr(NULL), count(NULL) // 构造时先初始化为NULL,再重设指针
{
reset(t);
}
~Ref()
{
dec();
}
Ref(const Ref &r)
{
*this = r;
}
Ref &operator=(const Ref &r)
{
dec(); // 先减少当前引用计数
ptr = r.ptr;
count = r.count;
inc();
return *this;
}
void reset(T *t) // 重设当前指针
{
dec(); // 先减少当前引用计数
ptr = t;
if (ptr)
{
count = new int;
*count = 1;
}
else count = NULL;
}
T *get() const
{
return ptr;
}
T *operator->() const
{
return ptr;
}
T &operator*() const
{
return *ptr;
}
int use_count() const
{
return count ? *count : 0;
}
};