智能指针

可能导致内存泄露的原因:

void Test()
{
 int *p = new int(1);
 if ()
 {
  return;
 }
 delete p;
}

此时,若执行if()语句,则指针p不能被释放,会造成内存泄漏。此过程为执行流跳转,可能会造成此过程的关键字有:return、break、continue、goto

若指针指向的空间可以自行释放,则不会出现这种问题。都知道,析构函数有这种功能,但是指针p知识一个常规指针,不是有析构函数的类对象指针。若为类对象指针,则在对象过期后,会自动调用析构函数释放指针指向的内存。这就是智能指针的基本思想。

实现智能指针

#include<iostream>
using namespace std;

template<class T>
class AutoPtr
{
public:
	explicit AutoPtr(T *ptr)
		:_ptr(ptr)
	{}

	AutoPtr(const T& ptr)
		:_ptr(ptr)
	{}

	~AutoPtr()
	{
		cout << "AutoPtr()" << endl;
		printf("0x%p", _ptr);
		delete _ptr;
	}

	T& operator*()
	{
		return *_ptr;
	}

	T* operator->()
	{
		return _ptr;
	}
private:
	T *_ptr;
};

void Func()
{
	int *p1 = new int(2);
	*p1 = 10;//解引用一个指针
	cout << *p1 << endl;

	AutoPtr<int> ap1(new int(1));
	*ap1 = 10;
}

int main()
{
	Func();
	return 0;
}

常见的智能指针有:std::auto_ptr,boost::scopped_ptr,boost::shared_ptr,boost::scoped_array,boost::shared_array,boost::weak_ptr。

一、std::auto_ptr实现

#include<iostream>
using namespace std;

//AutoPtr
template<class T>
class AutoPtr
{
public:
	//构造函数
	explicit AutoPtr(T *ptr)
		:_ptr(ptr)
	{}
	//拷贝构造
	AutoPtr(AutoPtr<T>& ap)//此处要修改ap的对象成员,所以不能加const
	{
		_ptr = ap._ptr;
		ap._ptr = NULL;
	}
	//赋值运算符重载
	AutoPtr<T>& operator=(AutoPtr<T>&ap)
	{
		if (this != &ap)
		{
			if (_ptr)
			{
				delete _ptr;
			}
			_ptr = ap._ptr;
			ap._ptr = NULL;//强行置空
		}
		return *this;
	}

	T& operator*()
	{
		return *_ptr;
	}

	T* operator->()
	{
		return _ptr;
	}

	~AutoPtr()
	{
		printf("0x%p", _ptr);
		delete _ptr;
	}
private:
	T *_ptr;
};

void TestAutoPtr()
{
	AutoPtr<int>ap1(new int(2));
	*ap1 = 10;
	cout << *ap1 << endl;
	AutoPtr<int>ap2(ap1);//AutoPtr<int>ap2=ap1
	AutoPtr<int>ap3(new int(2));
	ap3 = ap2;//赋值运算符重载
}

int main()
{
	TestAutoPtr();
	return 0;
}

ap1先将权限赋给ap2,两个指针指向同一块空间,ap2再将权限赋给ap3,三个指针指向同一块空间,调用析构函数时,三个对象都会调用析构函数,会导致一块空间释放三次,因此将实参的指针在结束后赋为空,与原意不符,因此舍弃。

二、boost::scoped_ptr实现

#include<iostream>
using namespace std;
template<class T>
class ScopedPtr
{
public:
 //构造函数
 ScopedPtr(T *ptr)
  :_ptr(ptr)
 {}
 //析构函数
 ~ScopedPtr()
 {
  if (_ptr)
  {
   delete _ptr;
  }
 }
 T& operator*()
 {
  return *_ptr;
 }
 T* operator->()
 {
  return _ptr;
 }
private:
 //只声明不实现
 ScopedPtr(const ScopedPtr<T>& sp);
 ScopedPtr<T>& operator=(const ScopedPtr<T>& sp);
private:
 T *_ptr;
};
void TestScopedPtr()
{
 ScopedPtr<int>sp1(new int(1));
 *sp1 = 10;
 cout << *sp1 << endl;
 //ScopedPtr<int>sp2(sp1);//  拷贝构造失败
 //ScopedPtr<int>sp3(new int(2));
 //sp3 = sp1;//赋值运算失败
}
int main()
{
 TestScopedPtr();
 return 0;
}


ScopedPtr指针通过将类中的拷贝构造函数以及赋值运算符重载函数声明,并不进行实现,为了不让使用者在后期使用的时候进行更改,将其放在private中。简单粗暴。这种方法称为防拷贝。

三、boost::shared_ptr

#include<iostream>
using namespace std;

template<class T>
class SharedPtr
{
public:
	SharedPtr(T* ptr)
		:_ptr(ptr)
		, _refCount(new int(1))
	{}

	SharedPtr(const SharedPtr<T>& sp)
	{
		_ptr = sp._ptr;
		_refCount = sp._refCount;
		(*_refCount)++;
	}

	SharedPtr<T>& operator=(SharedPtr<T>& sp)
	{
		if (_ptr != sp._ptr)
		{
			if (--(*_refCount) == 0)
			{
				delete _ptr;
				delete _refCount;
			}
			_ptr = sp._ptr;
			_refCount = sp._refCount;
			(*_refCount)++;
		}
		return *this;
	}

	~SharedPtr()
	{
		if (--(*_refCount) == 0)
		{
			printf("0x%p", _ptr);
			delete _ptr;
			delete _refCount;
		}
	}

	T& operator*()
	{
		return *_ptr;
	}

	T* operator->()
	{
		return _ptr;
	}

private:
	int *_ptr;
	int *_refCount;
};

void TestSharedPtr()
{
	SharedPtr<int> sp1(new int(10));
	*sp1 = 10;
	SharedPtr<int> sp2(sp1);
	cout << *sp1 << endl;
	cout<<*sp2<<endl;
	SharedPtr<int> sp3(new int(1));
	sp3 = sp2;
	cout << *sp3 << endl;
}

int main()
{
	TestSharedPtr();
	return 0;
}

在每个类中添加一个引用计数,有几个对象指针指向同一块内存空间,则这块内存空间的引用计数就是几,当引用计数为0时,这块空间就需要释放,当其中一个对象指针被赋予其它内存空间是,这个指针原先对应的那块空间的引用计数就需要减1。

总结

智能指针的发展历史

早期C++98

auto_ptr        ----管理权转移

boost非官方的库

scoped_ptr        ----守卫指针

shared_ptr         ----共享指针

weak_ptr           ----弱指针(不能单独存在)

C++11(将boost中的指针引入了标准库中)

unique_ptr

shared_ptr

weak_ptr

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值