C++——智能指针

作者:小 琛
欢迎转载,请标明出处

智能指针的提出

C++语言诞生时间较早,本身没有gc。(gc即垃圾回收器,不需要手动释放资源空间)
因此就有了本身编写代码容易出现的问题:内存空间泄露。又或者在某段代码抛异常后,就又可能发生异常安全的问题。

RAII思想的引入

RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。

在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。
借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:

  1. 不需要显示地释放资源
  2. 采用这种方式,对象所需的资源在其生命期内始终保持有效
//RAII思想
namespace RAII
{
	template <class T>
	class SmartPtr
	{
	public:
		SmartPtr( T* ptr = nullptr)
			:_ptr(ptr)
		{}
		~SmartPtr()
		{
			delete _ptr;
			_ptr = nullptr;
			std::cout << "delete _ptr" << std::endl;
		}
		T* operator ->()
		{
			return _ptr;
		}
		T& operator *()
		{
			return *_ptr;
		}
	private:
		T* _ptr;
	};
}
void text()
{
	RAII::SmartPtr<int> s(new int(1));
}
int main()
{
	text();
	return 0;
}

借助类的特性,会自动释放空间
在这里插入图片描述

C++引入的三大智能指针

  • auto_ptr(C++98引入)
    因缺陷明显,几乎已经被淘汰,不推荐使用
  • unique_ptr(C++11引入)
    推荐使用
  • shared_ptr(C++11引入)
    重点学习

auto_ptr的使用与缺陷

通过例子看简单使用与出现的问题:

#include <memory>
class Date
{
public:
 Date() { cout << "Date()" << endl;}
 ~Date(){ cout << "~Date()" << endl;}
 int _year;
 int _month;
 int _day;
};
int main()
{
 auto_ptr<Date> ap(new Date);
 auto_ptr<Date> copy(ap);
 // auto_ptr的问题:当对象拷贝或者赋值后,前面的对象就悬空了
 ap->_year = 2018;
 return 0;
 }

结果:
在这里插入图片描述
原因:auto_ptr对于拷贝构造时采用的是管理权转移法

当需要拷贝构造的时候,由于这里的类仅仅起到一个保管指针的作用,因此无法进行深拷贝。如果不加处理,可能导致一块空间被两个对象内的指针指向,从而在析构的时候出现一块空间被释放两次而崩溃。
在这里插入图片描述

  • 管理权转换法

对于上述的问题,auto_ptr采用管理权转换法,即如果要拷贝构造,将原来空间的指向权交给新的拷贝对象,将原来的指针悬空。
在这里插入图片描述

  • 新问题

管理权转换法带的新问题非常明显且严重,会直接将原来的指针悬空,像要再通过原来的指针操作就不可能了。因此在C++的发展中,它逐渐被淘汰了。

unique_ptr

C++11提出,思想简单粗暴,禁止该智能指针(类)的拷贝构造。

template <class T>
	class unique_ptr
	{
	public:
		unique_ptr(T* ptr = nullptr)
			:_ptr(ptr)
		{}
		~unique_ptr()
		{
			delete _ptr;
			_ptr = nullptr;
		}

		//暴力定义不支持拷贝构造和=
		unique_ptr(unique_ptr<T>& ap) = delete;
		unique_ptr<T>& operator=(unique_ptr<T>& ap) = delete;

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

更加靠谱的shared_ptr

shared_ptr的原理:是通过引用计数的方式来实现多个shared_ptr对象之间共享资源。即,通过计数的方式查看该智能指针(类)是否为最后一个指向该资源的对象,如果是进行空间释放,否则不进行。例如:最后一个离开的人再关灯锁门。

  1. shared_ptr在其内部,给每个资源都维护了着一份计数,用来记录该份资源被几个对象共享。
  2. 在对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减一。
  3. 如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源;
  4. 如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指针了。
    在这里插入图片描述
    这里增加了多线程的情况,考虑线程安全问题。
	template <class T>
	class shared_ptr
	{
	public:
		shared_ptr(T* ptr)
			:_ptr(ptr)
			, *_count(1)
		{}

		shared_ptr(shared_ptr<T>& ap)
			:_ptr(ap._ptr)
			,_count(ap._count)
		{
			//管理资源的成员数加1
			(*_count)++;
		}

		shared_ptr<T>& operator =(shared_ptr<T>& ap)
		{
			if (this != &ap)
			{
				//共同管理资源
				_ptr = ap._ptr;
				_count = ap._count;
				(*_count)++;
			}
			return *this;
		}

		~shared_ptr()
		{
			if (--(*_count) == 0)
			{
				delete _ptr;
				delete _count;
				_ptr = nullptr;
				_count = nullptr;
				std::cout << "delete shared_ptr" << std::endl;
			}
			else
			{
				_ptr = nullptr;
				_count = nullptr;
			}
		}
		T& operator *()
		{
			return _ptr;
		}
		T* operator ->()
		{
			return *_ptr;
		}
	private:
		T* _ptr;
		int* _count;
	};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小 琛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值