最近研究了一些智能指针的实现,基本都是基于引用计数的。但是网上的代码基本有同一个问题就是重复析构。如:C++面试题(四)——智能指针的原理和实现 和 C++中智能指针的工作原理和简单实现 都是这样的问题,用测试代码:
int main()
{
int *p=new int(2);
SmartPointer<int> p1=p;
SmartPointer<int> p2=p;
SmartPointer<int> p3;
p3=p1;
return 0;
}
在VC6.0中必然会在返回时出现程序崩溃的错误。(PS:不过用c-free5 gcc5.0编译器居然不会报错,貌似有安全机制重复释放的时候自动处理了)
言归正传,为了解决上述问题我对智能指针的类进行了升级,加入了全局映射表,保证每个地址的引用计数唯一,基本实现了安全使用。
文件名:SmartPtr.h
#include <map>
typedef std::map<void*, size_t*> SmartMap; //定义智能指针映射表类型
template <typename T>
class CSmartPtr
{
public:
//构造函数
CSmartPtr(T* pPtr = NULL): _ptr(pPtr)
{
if (pPtr)
{
//添加指针到映射表
AddSmartPtr(pPtr);
}
}
//拷贝构造
CSmartPtr(const CSmartPtr &src)
{
if (this != &src)
{
//添加指针到映射表
AddSmartPtr(src._ptr);
_ptr = src._ptr;
}
}
//重载赋值操作符
CSmartPtr& operator=(const CSmartPtr &src)
{
if (_ptr == src._ptr)
{
return *this;
}
//由于左值指向了其他地址,故引用计数减1
RemoveSmartPtr(_ptr);
//将右值加入到指针映射表中
AddSmartPtr(src._ptr);
_ptr = src._ptr;
return *this;
}
//重载基本操作符
T& operator *()
{
return *_ptr;
}
T* operator ->()
{
return _ptr;
}
//析构函数
~CSmartPtr()
{
RemoveSmartPtr(_ptr);
}
private:
T *_ptr;
static SmartMap _pSmartMap; //类的全局指针映射表 保存参数:指针地址,引用计数地址
void AddSmartPtr(T *pPtr)
{
SmartMap::iterator it;
it = _pSmartMap.find((void*)pPtr); //查找映射表
if (it != _pSmartMap.end())
{
++(*it->second); //表中存在该地址,则引用计数加1
return;
}
size_t *ref = new size_t(1); //初始引用计数设置为1
_pSmartMap.insert(SmartMap::value_type((void*)pPtr, ref)); //表中不存在,则添加到映射表中
}
void RemoveSmartPtr(T *pPtr)
{
SmartMap::iterator it;
it = _pSmartMap.find((void*)pPtr);
if (it != _pSmartMap.end())
{
if (--(*(it->second)) == 0) //引用计数为0,则删除对象
{
delete(T*)it->first;
delete it->second;
_pSmartMap.erase(it);
return;
}
}
}
};
//初始化类的静态变量
template <typename T>
SmartMap CSmartPtr<T>::_pSmartMap;
大家在使用的时候,包含一下头文件即可,VC6.0下测试运行良好。
测试代码如下:
int main(int argc, char* argv[])
{
int *p = new int(2);
CSmartPtr<int> p1 = p;
CSmartPtr<int> p2 = p;
CSmartPtr<int> p3;
p3 = p1;
return 0;
}