智能指针--RAII

智能指针:RAII全称为Resource Acquisition Is Initialization,它是在一些面向对象语言中的一种惯用法。RAII源于C++,在JavaC#DAdaValaRust中也有应用。是为了解决资源管理时的异常安全性提出了该用法。实现了普通指针的指向和解引用的功能,并实现在类的对象构造时初始化对象和析构时负责释放资源

RAII要求,资源的有效期与持有资源的对象的命期严格绑定,即由对象的构造函数完成资源的分配(获取),同时由析构函数完成资源的释放。在这种要求下,只要对象能正确地析构,就不会出现资源泄露问题。

异常安全性

1.抛出异常后,资源不泄露

2.抛出异常后,不会使原有数据恶化(例如正常指针变野指针)

3.少些 try catch ,因为⼤量的 try catch 会影响代码逻辑。导致代码丑陋混乱不优雅

auto_ptr所做的事情,就是动态分配对象以及当对象不再需要时自动执行清理,可想象为管理权转移。auto_ptr有着严重的缺陷,建议尽量不使用。

//AutoPtr管理权转移
template <class T>
class AutoPtr
{
public:
	AutoPtr( T* ptr)
		:_ptr(ptr)
	{}
	AutoPtr(AutoPtr <T>& p)
	{
		this->_ptr = p._ptr;
		p._ptr = NULL;
	}
	~AutoPtr()
	{
		cout << "~AutoPtr()" << endl;
		delete _ptr;
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
	AutoPtr<T>& operator=(AutoPtr<T>& p)
	{
		if (this != &p)
		{
			delete this->_ptr;
			this->_ptr = p._ptr;
			p._ptr = NULL;
		}
		
		return *this;
	}

protected:
	T* _ptr;
};

scoped_ptr有着更严格的使用限制——不能拷贝(即只声明,不定义)。这就意味着scoped_ptr指针是不能转换其所有权的。

//ScopedPtr防拷贝,只声明,不定义
template <class T>
class ScopedPtr
{
public:
	ScopedPtr(T* ptr)
		:_ptr(ptr)
	{}
	~ScopedPtr()
	{
		cout << "~ScopedPtr()" << endl;
		delete _ptr;
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
	//将拷贝构造和operator= 设为保护,防拷贝
protected:
	ScopedPtr (ScopedPtr<T>& p);
	ScopedPtr& operator=(ScopedPtr<T>& p);
	
protected:
	T* _ptr;
};

shared_ptr通过使用引用计数,它解决了在多个指针间共享对象所有权的问题,同时也满足容器对元素的要求,因而可以安全地放入容器中。缺点:存在循环引用的问题


循环引用举例:

class B;
class A {
public:
    shared_ptr<B> p;
};

class B {
public:
    shared_ptr<A> p;
};

int main() {
    while (true) {
        shared_ptr<A> pa(new A());
        shared_ptr<B> pb(new B());
        pa->p = pb;
        pb->p = pa;
    }
    return 0;
}

while循环中,先是在栈中构造了两个智能指针,分别管理两块堆内存,记为A, B。然后两个赋值语句,使得在shared_ptr中,AB的引用计数均为2,所以在析构掉papb时,他们的引用计数都没能到达0,于是发生了循环引用,于是开始内存泄露

//仿函数
template <class T>
class Delete
{
public:
	void operator()(T* ptr)
	{
		cout << "delete" << endl;
		delete ptr;
	}
};
template <class T>
class DeleteArray
{
public:
	void operator()(T* ptr)
	{
		cout << "delete[]" << endl;
		delete[] ptr;
	}
};
template <class T>
class Fclose
{
public:
	void operator()(T* ptr)
	{
		cout << "fclose" << endl;
		fclose(ptr);
	}
};
template <class T>
class Free
{
public:
	void operator()(T* ptr)
	{
		cout << "free" << endl;
		free(ptr);
	}
};

//ShareaPtr引入引用计数
template <class T,class Del=Delete<int>>
class SharedPtr
{
public:
	SharedPtr(T* ptr)
		:_ptr(ptr)
		, _Count(new int(1))
	{}
	~SharedPtr()
	{
		cout << "~SharedPtr()" << endl;
		Clear();
	}
	SharedPtr(SharedPtr <T,Del>& p)
		:_ptr(p._ptr)
		, _Count(p._Count)
	{
		++(*_Count);
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
	SharedPtr<T,Del>& operator=(SharedPtr <T,Del>& p)
	{
		if (this != &p)
		{
			Clear();
			_ptr = p._ptr;
			_Count = p._Count;
			++(*_Count);
		}
		return *this;
	}
	void Clear()
	{
		if (--(*_Count) == 0)
		{
			cout << "delete" << endl;
			//delete _ptr;
			_del(_ptr);
			delete _Count;
		}
	}

protected:
	T* _ptr;
	int* _Count;
	Del _del;
};

循环引用解决:

weak_ptr是为配合shared_ptr而引入的一种智能指针来协助shared_ptr工作,它可以从一个shared_ptr或另一个weak_ptr对象构造,它的构造和析构不会引起引用记数的增加或减少。没有重载*->但可以使用lock获得一个可用的shared_ptr对象

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值