c++—智能指针

在c++中,动态内存的管理是通过一对运算符来完成的:

new
  //在动态内存中为对象分配空间并返回一个指向该对象的指针,我们并可以选择对对象初始化
delete
  // 接受一个动态对象的指针,销毁该对象,并释放与之关联的内存

动态内存的使用很容易出现问题,因为确保在正确的时间释放内存是相当困难的,有时我们会忘记释放内存,在这种情况下会产生内存泄漏,有时在尚有指针引用内存的情况下我们就释放了它,在这种情况下就会产生引用非法内存的指针。

int* p = new int[10];
FILE *pfile = fopen("smart_pointer.cpp", "r");
if (pfile == NULL)
{
	return;      //当文件不存在时,就会导致内存泄露
}
if (p)
{
	delete[]p;
	p = NULL;
}

为了更容易的使用动态内存,新的标准库提出了两种智能指针来管理动态对象,智能指针的行为类似于常规指针,重要的区别是,它负责自动释放所指向的对象,在新的标准库中提出了一种思想,RAII(资源分配与初始化),这是一种规范,一种解决问题的思想,类似于定义一个类,构造函数(资源分配与初始化),析构函数(清理资源与释放空间),其中智能指针就是RAII的一种应用,智能的管理着指针释放的问题



//c++标准库中
#include<memory.h>
shared_ptr      //允许多个指针指向同一个对象
unique_ptr      //“独占”所指向的对象
weak_ptr        //伴随类,弱引用,指向shared_ptr所管理的对象

模拟实现auto_ptr(只可以管理一个对象)

#include <iostream>
#include <string.h>
using namespace std;
template <class T>
class Autoptr
{
public:
	Autoptr(T * ptr)
		:_ptr (new T(1))
	{
			_ptr = ptr;
			cout << "Autoptr()" << endl;
	}
	Autoptr(Autoptr& ptr)
		:_ptr (ptr._ptr)
	{
			cout << "Autoptr(Autoptr& ptr)" << endl;
			ptr._ptr = NULL;

	}
	Autoptr<T>& operator= (Autoptr& ptr)
	{
		cout << "Autoptr<T>& operator= (Autoptr& ptr)" << endl;
		if (this != &ptr)
		{
			delete this->_ptr;
			_ptr = ptr._ptr;
			ptr._ptr = NULL;
		}
		return *this;
	}
	T& operator*()     //*重载
	{
		return *_ptr;
	}
	T* operator->()    //->重载
	{
		return _ptr;
	}
	~Autoptr()
	{
		cout << "~Autoptr()" << endl;
		if (_ptr)
		{
			delete _ptr;
			_ptr = NULL;
		}
	}
	
private:
	T *_ptr;

};
void Funtest1()
{
	Autoptr<int> ptr = new int;
	*ptr = 10;
	Autoptr<int> ptr1(ptr);
	cout << *ptr1<< endl;
	
}
int main()
{
	Funtest1();
	return 0;
}

这里写图片描述

auto_ptr弊端:只能对单个对象进行管理,每次只有一个对象可使用申请的空间,当资源转移给另一个对象使用时,前一个对象就会赋值为空。

当了解了auto_ptr的功能,我们可以用另一种思路来实现它,定义一个私有成员来标记当前对象的状态,当对象正在占用空间时,定义为true,当对象不再指向任何空间时,定义为false. 不过还是切记不要使用auto_ptr;

模拟实现scoped_ptr
与 auto_ptr 一样,都是管理单个对象的, 它的作用是:在一个类中防止拷贝,或许我们可以认为,把它定义为私有的,其实并不然,因为访问私有成员或函数的方式还是会调用函数声明,在这里,我们学习一种新的防拷贝方式:只声明不定义,且将拷贝构造与赋值运算符重载声明为私有即可
代码如下:

实现scoped_ptr

template <class T>
class Scopedptr
{
public:
     Scopedptr( T* ptr)
		 :_ptr(new T)
	 {
			 _ptr = ptr;
	 }
	 ~Scopedptr()
	{
		 if (_ptr)
		 {
			 delete _ptr;
			 _ptr = NULL;
		 }
	 }
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}

private:
	Scopedptr(const Scopedptr&);
	Scopedptr<T>& operator=(const Scopedptr&);
	T* _ptr;
};
void Funtest1()
{
	Scopedptr<int> p = new int;
	*p = 10;
	cout << *p << endl;
	/*Scopedptr<int>p1(p);
	Scopedptr<int> p2 = p;*/
}
int main()
{
	Funtest1();
	return 0;
}

scoped_ptr 的实现机制体现了它的独占性,当一个对象占用空间时, 其他对象将无法使用,并且实现不了资源的转移。

注:在STL源码库中,使用的是scoped_ptr 而在boost库中,使用的是unique_ptr,其实两个完全一样

shared_ptr:可以管理多个对象他们之间的资源是共享的(用引用计数的方法实现)

template <class T>
class Sharedptr
{
public:
	Sharedptr(T* ptr =NULL)
		:_ptr(ptr)
		,_pcount(new int(1))
	{}
	Sharedptr(Sharedptr& p)
		:_ptr(p._ptr)
		, _pcount(p._pcount)
	{
	    ++*(_pcount);
	}
	Sharedptr<T>& operator=(Sharedptr& p)
	{
	
		if (_ptr != p._ptr)
		{
			if (_ptr == NULL)
			{
				_ptr = p._ptr;
				_pcount = p._pcount;
			}
			else if (_ptr && (*_pcount == 1))
			{
				delete _ptr;
				_ptr = p._ptr;
				_pcount = p._pcount;
			}
			else
			{
				--(*_pcount);
				_ptr = p._ptr;
				_pcount = p._pcount;	
			}
			if (p._ptr)
			{
				++(*_pcount);
			}
		}
		return *this;
	}
     ~Sharedptr()
	{
		if (_ptr && --(*_pcount) == 0)
		{
			delete _ptr; 
			_ptr = NULL;
		}
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
	int Get_pcount()
	{
		if (_pcount != NULL)
			return *_pcount;
		return 0;
	}
private:
	T* _ptr;
	int * _pcount;
};

int main()
{
	Sharedptr<int> ps = new int(1);
	Sharedptr<int> ps1(ps);//ps1是由ps拷贝构造出来的,此操作会递增ps中的引用计数,
	Sharedptr<int> ps2;
	ps2 = ps1;//ps1与ps2都是Sharedptr,所保存的指针必须可以相互转化,此操作会递减ps2的引用计数,递增q的引用计数,若ps2的引用计数为0,则将其管理的原内存释放
	cout << ps.Get_pcount() << endl;
	cout << ps1.Get_pcount() << endl;
	cout << ps2.Get_pcount() << endl;
	return 0;
}
我们可以认为,每个shareptr都有一个关联的计数器,无论何时我们拷贝一个shareptr,计数器都会递增,例如,当用一个对象去初始化另一个对象时,或者将其作为参数传递给一个函数,以及作为函数的返回值,他所关联的计数器都会递增,当我们给shareprt赋予一个新值,或者shareptr被销毁时,计数器就会递减,一旦有一个计数器变为了0,就会自动释放(通过析构函数来完成收尾工作)所管理的内存。

weak_ptr
是一种不控制所指向对象生存周期的智能指针,他指向由一个shared_ptr所管理的对象,将一个 weak_ptr绑定到一个shared_ptr不会改变shareptr的引用计数,一旦最后一个指向对象的shareptr被销毁时,对象就会被释放,即使有weak_ptr指向对象,对象也还是会被释放,因此weak_ptr的名字抓住了这种智能指针“”弱“”共享的特点

当我们创建一个weak_ptr时,会用shareptr来初始化
Sharedptr<int> ps = new int(1);
weak_ptr<int> ps1(ps);//ps1弱共享ps,ps的引用计数未发生改变,ps1所指向的对象可能会被释放掉
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值