【C++】智能指针的学习

目录

unique_ptr:

shared_ptr:

 weak_ptr:


        经过异常的学习,我知道抛异常如果不注意是有可能造成资源泄漏的问题的,那么如何避免这种问题同时还能很好地抛异常呢?    

RAII是一种利用对象生命周期来控制程序资源的技术 (其实也是一种指导思想):

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

	~smartPtr()
	{
		cout << "delete[]" <<_ptr<< endl;
		delete[] _ptr;
	}

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

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

 这就是一个简单的RAII指导写出来的智能指针(auto_ptr)的一小部分 

在对象构造的时候获取资源,在对象析构的时候释放资源

采用这种方法,对象所需要的资源在其生命周期内始终保持有效

        auto_ptr里面比较难解决的是它的赋值拷贝问题 ,如果采用类自己生成的赋值构造函数是不行的,默认的构造函数对于内置类型采用值拷贝,自定义类型调用该类型的拷贝构造。

        值拷贝的话,就会面临重复delete的情况,针对这种情况,auto_ptr采用资源转移的方式,新对象来管理这份资源,原来的对象管理资源的指针置空

unique_ptr:

这个智能指针针对赋值拷贝问题的解决办法会比较暴力一些,它是直接让赋值拷贝函数不生成 

        unique_ptr(const unique_ptr<T>& ptr) = delete;
		unique_ptr<T>& operator=(const unique_ptr<T>& ptr) = delete;

shared_ptr:

shared_ptr:就是要求需要能够进行赋值拷贝,那该怎么处理资源清理的问题呢

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

		~shared_ptr()
		{
			release();
		}

		void release()
		{
			if (--(*_pCount) == 0)
			{
				delete _ptr;
				_ptr = nullptr;

				delete _pCount;
				_pCount = nullptr;
			}
		}

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

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

		T* Get()
		{
			return _ptr;
		}

		shared_ptr(const shared_ptr<T>& sp) :_ptr(sp._ptr), _pCount(sp._pCount)
		{
			(*_pCount)++;
		}

		shared_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			if (_ptr != sp._ptr)
			{
				release();

				_ptr = sp._ptr;
				_pCount = sp._pCount;
				(*_pCount)++;
			}
			return *this;
		}
	private:
		T* _ptr;
		int* _pCount;
	};

        shared_ptr里面需要注意,我们使用的引用计数的加减问题,比如:当我们再进行赋值的时候,一个指针被赋值,那他就不再指向之前的资源了,所以需要再赋值之前对原来资源的引用计数进行减减

        shared_ptr还存在一个循环引用的问题 :

struct listnode {
	std::shared_ptr<listnode> a;
	std::shared_ptr<listnode> b;
};

int main()
{

	std::shared_ptr<listnode> sp1(new listnode);
	std::shared_ptr<listnode> sp2(new listnode);
	
	sp1->a = sp2;
	sp2->b = sp1;

}

 大家看现在的这个代码就已经构成了循环引用的问题了

         sp1 和 sp2 释放后,a和b都是自定义成员变量,析构需要调用自己的析构函数,a想要调用自己的析构函数就需要b释放,b释放需要a调用自己的析构函数释放,这样就构成循环引用的问题了

 weak_ptr:

template<class T>
	class weak_ptr
	{
	public:
		weak_ptr():_ptr(nullptr) {}

		~weak_ptr()
		{
		}


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

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

		T* Get()
		{
			return _ptr;
		}

		weak_ptr(const shared_ptr<T>& sp) :_ptr(sp.Get())
		{

		}

		weak_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			if (_ptr != sp.Get())
			{
				_ptr = sp.Get();
			}
			return *this; 
		}
	private:
		T* _ptr;
	};
    struct listnode {
	zcj::weak_ptr<listnode> a;
	zcj::weak_ptr<listnode> b;
};

int main()
{

	zcj::shared_ptr<listnode> sp1(new listnode);
	zcj::shared_ptr<listnode> sp2(new listnode);
	
	cout<<sp1.use_count();
	cout << sp2.use_count();

	sp1->a = sp2;
	sp2->b = sp1;

	cout << sp1.use_count();
	cout << sp2.use_count();
}

weak_ptr:起到指向资源,但是不参与资源清理的工作,依然也是可以通过weak_ptr访问和修改资源的。


这只是我们自己设置的结构体,那不同的资源有不同的释放的方法,可是要注意一点哦我们的智能指针默认的释放方式是delete。 

        可以看到我们是可以通过自定义仿函数的方式,这样应对不同的资源,由于我们自己知道自己申请的资源的释放方式是什么所以,所以可以自定义 。

        不同的是shared_ptr,是通过构造函数传进去的

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值