今天看了zthread库中的计数指针,于是也参考着在vs2010上写了一个来巩固对计数指针的理解
#pragma once
template<typename TypeInstance, typename TypeCount = int>
class MyCountPtr
{
//引用计数指针只要以下两个数据成员
//指向对象
TypeInstance* t_instance;
//指向计数器,计数器默认为int类型
TypeCount* t_count;
public:
MyCountPtr()
: t_instance(NULL)
, t_count(NULL)
{
}
//如果传的参数为空指针,调用以下函数构造,std::nullptr_t为空指针类型
#if defined(_NATIVE_NULLPTR_SUPPORTED) \
&& !defined(_DO_NOT_USE_NULLPTR)
MyCountPtr(std::nullptr_t)
: t_instance(NULL)
, t_count(NULL)
{
std::cout<<"constructor parameter is null\n";
}
#endif
//计数指针一般在MyCountPtr对象对t_instance对象进行引用,或解除引用时发生变化
//1、MyCountPtr<TypeInstance, TypeCount>::MyCountPtr(std::nullptr_t)
//2、MyCountPtr<TypeInstance, TypeCount>::MyCountPtr<Instance>(innstance* ins)
//该模版构造函数不需要考虑用户传空指针,传空指针会调用函数1
//如果不定义为模版函数,则与函数1就变为重载函数,当参数传NULL时,编译器就无法确定调用哪个版本
//使用时一般使Instance与TypeInstance一致,若不一致必须保证两个类型能够相互转化
template<typename Instance>
explicit MyCountPtr(Instance* ins)//explicit拒绝隐式转换,否则编译器会在某些时候将TypeInstance*对象转换成MyCountPtr对象,可能这个结果不是我们想要的
: t_instance(ins)
, t_count(new TypeCount())
{
++(*t_count);
}
//拷贝构造
MyCountPtr(const MyCountPtr& rh)
: t_instance(rh.t_instance)
, t_count(rh.t_count)
{
if(t_count)
++(*t_count);
}
//=重载
MyCountPtr& operator=(const MyCountPtr& rh)
{
MyCountPtr<TypeInstance, TypeCount> rhCopy(rh);
rhCopy.swap(*this);
return *this;
}
//重置对象
void Reset()
{
MyCountPtr<TypeInstance, TypeCount> empty;
empty.swap(*this);
}
//析构,引用计数为0时,释放对象
~MyCountPtr()
{
if(t_count && --(*t_count) == 0)
{
if(t_instance)
{
std::cout<<"delete instance "<<*t_instance<<std::endl;
delete t_instance;
}
delete t_count;
}
}
//操作符类型转化,将自身转化为bool类型
operator bool()
{
return t_instance != NULL;
}
//!操作符重载,专用于判断所管理的对象是否为空
bool operator!()
{
return t_instance == NULL;
}
//取值运算符重载,取管理的对象指针
TypeInstance& operator*()
{
return *t_instance;
}
//反引用符重载,使本对象可以间接调用t_instance对象指针访问他的接口
TypeInstance* operator->()
{
return t_instance;
}
private:
//调用标准库的swap直接交换指针实现对象的数据交换
void swap(MyCountPtr& rh)
{
std::swap(t_count, rh.t_count);
std::swap(t_instance, rh.t_instance);
}
};
测试代码
#include <iostream>
#include "MyCountPtr.h"
int main()
{
MyCountPtr<int> sp1(new int(2));
{
MyCountPtr<int> sp(new int(1));
//赋值前 sp1为2,引用计数为1,sp为1,引用计数为1
sp1 = sp;
}//出括号作用域时输出delete instance 2
{
MyCountPtr<int> sp2(sp1);
//此时 sp1和sp2管理的对象值为1,引用计数为2
}//出括号作用域时sp1管理的对象值为1,引用计数为1
MyCountPtr<int> p(NULL);//调用空指针参数的构造函数,输出constructor parameter is null
MyCountPtr<int> p1(new int(3));
MyCountPtr<int> p2(new int(4));
p1.Reset();//函数返回后输出delete instance 3
return 0;
}//出函数作用域时依次输出delete instance 4,delete nstance 1
//4后创建,后创建的靠近栈顶,先销毁
注:开源库的代码一般都很值得程序员研究和学习,简单的几句话可能蕴含着很多技巧,如赋值操作符和Reset函数实现中用了临时变量去和本对象进行数据交换不但巧妙,而且代码优雅。