(未完)【C/C++】C++智能指针

我们知道堆上申请的空间必须通过手动释放来回收,如果忘记这一点,很容易造成内存泄漏。智能指针的引入就是为了解决如何在正确的时机(已经没有利用价值)释放堆上申请的空间,其实现原理是通过在指针外面包一层类,并在栈上生成此类的对象,当它在栈上被自动回收的时候,将堆上的空间也释放掉。

1. 重新造一个轮子

自定义智能指针遵循以下两个原则:
1). 智能指针类必须定义为类模板,这样才能hold住所有具体类
2). 引用计数必须包含在具体类中,即只在最源头保存一个引用计数

ReferenceCounted.h

所有具体类必须继承自ReferenceCounted类。其内部包含引用计数,当被一个SmartPtr引用时就自增,当一个SmartPtr被回收时就自减。当引用计数减为0时,通过调用delete this显式地将自己回收。
#ifndef REFERENCECOUNTED_H
#define REFERENCECOUNTED_H

class ReferenceCounted
{
public:
	ReferenceCounted()
	{
		referenceCounter = 0;
	}
	void AddRef()
	{
		++referenceCounter;
	}
	void Release()
	{
		if (referenceCounter > 0 && --referenceCounter == 0)
		{
			delete this;
		}
	}
protected:
	// 虚析构函数!
	virtual ~ReferenceCounted(){}
private:
	// 引用计数
	int referenceCounter;
};

#endif

SmartPtr.h

SmartPtr类被定义为类模板,可以接收任何继承自ReferenceCounted类的具体类。
#ifndef SMARTPTR_H
#define SMARTPTR_H

// ReferenceCountedT必须是一个继承自ReferenceCounted的类
template <class ReferenceCountedT>
class SmartPtr
{
public:
	// 构造函数一:传入类型为ReferenceCountedT的指针来构造SmartPtr,必须保证p所指向的内容在堆上
	SmartPtr(ReferenceCountedT *p);
	// 构造函数二:拷贝构造函数,用一个SmartPtr来构造另一个SmartPtr
	SmartPtr(const SmartPtr<ReferenceCountedT> &p);
	~SmartPtr();
	// 重载赋值运算符一:必须保证p所指向的内容在堆上
	SmartPtr& operator =(const ReferenceCountedT *p);
	// 重载赋值运算符二:智能指针间赋值
	SmartPtr& operator =(const SmartPtr<ReferenceCountedT> &p);
	// 重载取值运算符
	ReferenceCountedT& operator *() const;
	// 重载成员选择运算符
	ReferenceCountedT* operator ->() const;
	// 重置SmartPtr的内部指针
	void Reset(ReferenceCountedT *p = NULL);
	// 获得内部指针
	ReferenceCountedT* Get();
private:
	void Dispose();
	ReferenceCountedT *ptr;
};

// 用法
// ReferenceCounted *p = new ReferenceCounted();
// SmartPtr<ReferenceCounted> sp(p);
template <class ReferenceCountedT>
SmartPtr<ReferenceCountedT>::SmartPtr(ReferenceCountedT *p)
{
	ptr = p;
	if (ptr)
	{
		ptr->AddRef();
	}
}

// 用法
// ReferenceCounted *p = new ReferenceCounted();
// SmartPtr<ReferenceCounted> sp1(p);
// SmartPtr<ReferenceCounted> sp2(sp1);
template <class ReferenceCountedT>
SmartPtr<ReferenceCountedT>::SmartPtr(const SmartPtr<ReferenceCountedT> &p)
{
	ptr = p.ptr;
	if (ptr)
	{
		ptr->AddRef();
	}
}

template <class ReferenceCountedT>
SmartPtr<ReferenceCountedT>::~SmartPtr()
{
	Dispose();
}

template <class ReferenceCountedT>
SmartPtr<ReferenceCountedT>& SmartPtr<ReferenceCountedT>::operator =(const ReferenceCountedT *p)
{
	Reset(p);
	return *this;
}

template <class ReferenceCountedT>
SmartPtr<ReferenceCountedT>& SmartPtr<ReferenceCountedT>::operator =(const SmartPtr<ReferenceCountedT> &p)
{
	Reset(p.ptr);
	return *this;
}

template <class ReferenceCountedT>
ReferenceCountedT& SmartPtr<ReferenceCountedT>::operator *() const
{
	return *ptr;
}

template <class ReferenceCountedT>
ReferenceCountedT* SmartPtr<ReferenceCountedT>::operator ->() const
{
	return ptr;
}

template <class ReferenceCountedT>
void SmartPtr<ReferenceCountedT>::Reset(ReferenceCountedT *p)
{
	// 避免自赋值self-assignment
	if (ptr != p)
	{
		Dispose();
		ptr = p;
		if (ptr)
		{
			ptr->AddRef();
		}
	}
}

template <class ReferenceCountedT>
ReferenceCountedT* SmartPtr<ReferenceCountedT>::Get()
{
	return ptr;
}

template <class ReferenceCountedT>
void SmartPtr<ReferenceCountedT>::Dispose()
{
	if (ptr)
	{
		ptr->Release();
	}
}

#endif
测试代码:

MyClass.h

MyClass类表示一个具体类,继承自ReferenceCounted。
#include "ReferenceCounted.h"

class MyClass : public ReferenceCounted
{
public:
	MyClass()
	{
		num = 0;
	}
	int MyFoo()
	{
		++num;
		return num;
	}
	int num;
protected:
	~MyClass(){}
};

Main.cpp

#include "SmartPtr.h"
#include "MyClass.h"
#include <crtdbg.h>
#include <vector>
#include <iostream>
using namespace std;

void main(void)
{
	{
		MyClass *rc1 = new MyClass();
		SmartPtr<MyClass> sp1 = rc1; // 普通构造函数
		SmartPtr<MyClass> sp2 = sp1; // 拷贝构造函数
		SmartPtr<MyClass> sp3(rc1); // 普通构造函数
		SmartPtr<MyClass> sp4(sp1); // 拷贝构造函数

		MyClass *rc2 = new MyClass();
		sp3 = rc2; // 赋值运算符
		sp4 = sp3; // 赋值运算符

		cout << (*sp1).MyFoo() << endl; // 像指针一样操作
		cout << sp1->MyFoo() << endl;

		vector<SmartPtr<MyClass>> v; // 在vector中的表现
		v.push_back(sp1);
		v.push_back(sp2);
		v.push_back(sp3);
		v.push_back(sp4);
	}
	_CrtDumpMemoryLeaks();
}

2. C++自带智能指针研究


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值