智能指针的一种实现

下面是实现智能指针的一种方式,原理就是实现并自动处理引用计数操作的C++模板。

#ifndef SMARTPTR_H
#define SMARTPTR_H

template <class T> class SmartPtr;


// IRefCount
// 是引用计数的接口
// 类应该自己实现它
// 或者 SmartPtr 会提供它的 IRefCount 的内部实现
template <class T> class IRefCount
{
	friend class SmartPtr<T>;
protected:
	virtual void AddRef() = 0;
	virtual void Release() = 0;
	virtual T * GetPtr() const = 0;
};


// IRefCountImpl
// 是 IRefCount 的标准实现
// 要使用的话直接从其派生,比如
// class CMyObject : public IRefCountImpl<CMyObject> { ... }
// 注意:实现 IRefCount 是可选的,但这么做可以减少内存碎片
template <class T> class IRefCountImpl
	: public IRefCount<T>
{
private:
	int m_Count;
protected:
	virtual void AddRef() { m_Count++; }
	virtual void Release()
	{
		assert(m_Count >= 0);
		m_Count--;
		if(m_Count <= 0)
		{
			Destroy();
		}
	}
	virtual T * GetPtr() const { return ((T *)this); }
	virtual void Destroy()
	{
		if(GetPtr() != NULL)
			delete GetPtr();
	}
	
	IRefCountImpl() { m_Count = 0; }
};


// SmartPtr
template <class T> class SmartPtr
{
private:
	IRefCount<T> * m_RefCount;
	
	
	// RefCounter
	// 为没有实现 IRefCount 的类提供内部实现
	// SmartPtr会自动选择内部实现或者实现 IRefCount 的类
	class RefCounter : public IRefCountImpl<T>
	{
	private:
		T * m_Ptr;
	protected:
		virtual T * GetPtr() const { return m_Ptr; }
		virtual void Destroy() { delete this; }
	public:
		RefCounter (T * ptr) { m_Ptr = ptr; }
		virtual ~RefCounter() { IRefCountImpl<T>::Destroy(); }
	};
	
	// 如果T没有实现IRefCount,这个方法会被调用
	void Assign(void * ptr)
	{
		if(ptr == NULL)
			Assign((IRefCount<T> *)NULL);
		else
		{
			Assign(new RefCounter(static_cast<T *>(ptr)));
		}
	} 
	
	// 如果T实现了 IRefCount,这个方法会代替Assign(void * ptr)
	// 这使得一些内存使用优化
	void Assign(IRefCount<T> * refcount)
	{
		if(refcount != NULL)
			refcount->AddRef();
		IRefCount<T> * oldref = m_RefCount;
		m_RefCount = refcount;
		if(oldref != NULL)
			oldref->Release();
	} 
public:
	SmartPtr() { m_RefCount = NULL; }
	SmartPtr(T * ptr) { m_RefCount = NULL; Assign(ptr); }
	SmartPtr(const SmartPtr & sp) { m_RefCount = NULL; Assign(sp.m_RefCount); }
	virtual ~SmartPtr() { Assign((IRefCount<T> *)NULL); }
	
	T * GetPtr() const { return (m_RefCount == NULL) ? NULL : m_RefCount->GetPtr(); }
	
	// 赋值操作符
	SmartPtr& operator = (const SmartPtr & sp)
	{
		Assign(sp.m_RefCount);
		return * this;
	} 
	SmartPtr& operator = (T * ptr)
	{
		Assign(ptr);
		return * this;
	}
	
	// T访问和const转换
	T * operator ->()
	{
		assert(GetPtr() != NULL);
		return GetPtr();
	} 
	operator T* () const { return GetPtr(); }
	
	// 工具
	bool operator !()
	{
		return GetPtr() == NULL;
	} 
	bool operator ==(const SmartPtr &sp)
	{
		return GetPtr() == sp.GetPtr();
	}
	bool operator !=(const SmartPtr &sp)
	{
		return GetPtr() != sp.GetPtr();
	}
};
#endif

下面是使用这个模板的例子:


// SmartPtr.cpp
// 如何使用 SmartPtr 的例子
#include <stdio.h>
#include <assert.h>
#include "smartptr.h"

// 定义一个自己的类用来测试 
class CMyObject
{
	char *name;
public:
	CMyObject(char *aname)
	{
		name = aname;
		printf("create %s\n", name);
	}
	virtual ~CMyObject()
	{
		printf("delete %s\n", name);
	}
	void print()
	{
		printf("print %s\n", name);
	}
};

//  测试作为返回值使用
SmartPtr<CMyObject> f1(char *name)
{
	return SmartPtr<CMyObject>(new CMyObject(name));
} 

// 测试作为参数使用 
void f2(CMyObject *o)
{
	printf("(print from a function)");
	o->print();
} 

int main()
{
	SmartPtr<CMyObject> ptr1(new CMyObject("1"));	// 创建对象“1”
	SmartPtr<CMyObject> ptr2 = new CMyObject("2");	// 创建对象“2”
	
	ptr1 = ptr2;	// 销毁对象“1”
	ptr2 = f1("3");	// 作为返回值使用
	ptr2 = NULL;	// 销毁对象“3”

	/* 错误的用法 	
	CMyObject o1;
	ptr1 = &o1;		// 不能这么赋值,因为 o1 在栈上
	
	CMyObject * o2 = new CMyObject;
	ptr1 = o2;
	ptr2 = o2;		// 不能这么做,除非CMyObject实现了IRefCount接口 
	*/
	// 甚至可以在整数上用 SmartPtr
	SmartPtr<int> a(new int);
	SmartPtr<int> b(new int);
	
	*a = 5;
	*b = 6;
	
	// 没有内存泄漏!!!
	return 0; 
}
只要SmartPtr对象在作用域内,而且避免那些错误用例,就不会造成内存泄漏。然而,智能指针并不是在每种情况下都能使用的。一个局限就是它不能在多线程的环境下使用。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值