【C++】智能指针

目录

一.什么是智能指针?

二.为什么需要智能指针??

三. 思维导图

 四.模拟实现三个智能指针

1.auto_ptr

 2.unique_ptr

3.shared_ptr

shared_ptr的线程安全问题和循环引用的解决方法下篇文章在做分享


一.什么是智能指针?

     智能指针包括两部分:

      1.RAII

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

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

  • 不需要显式地释放资
  • 采用这种方式,对象所需的资源在其生命期内始终保持有

      2.像指针一样(实现像指针一样的功能)

  • 重载operator*
  • 重载operator->

   二.为什么需要智能指针??

为了更好的解决以下两个问题所以出现了智能指针

1.当我们malloc出来的内存没有去释放时就会出现问题,就会存在内存泄漏问题

2.异常安全问题。当在malloc和delete之间出现出现抛异常时,那么也会出现安全异常问题

三. 思维导图

代码:

template<class T>

class SmartPtr
{
public:

	//RAII
	SmartPtr(T* ptr = nullptr)
		:_ptr(ptr)
	{}
	~SmartPtr()
	{
		if (_ptr)
			free _ptr;
	}

	//像指针一样
	T& operator*()
	{
		return *_ptr;
	}

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

void MergeSort()
{
	int* tmp = new int;
	// 讲tmp指针委托给了sp对象,用时老师的话说给tmp指针找了一个可怕的女朋友!天天管着你,直到你go 
		SmartPtr<int> sp(tmp);
	// _MergeSort(a, 0, n - 1, tmp);


	// 这里假设处理了一些其他逻辑
	vector<int> v(1000000000, 10);
	// 
}

struct Date
{
	int _year;
	int _month;
	int _day;
};

int main()
{
	SmartPtr<int> sp1(new int);
	*sp1 = 10;
		cout << *sp1 << endl;

		SmartPtr<int> sparray(new Date);
	// 需要注意的是这里应该是sparray.operator->()->_year = 2018;
	// 本来应该是sparray->->_year这里语法上为了可读性,省略了一个->
	sparray->_year = 2018;
	sparray->_month = 1;
	sparray->_day = 1;
	system("pause");
	return 0;
}

 四.模拟实现三个智能指针

这些智能指针的头文件在#inlude<memory>中

1.auto_ptr

auto_ptr是C++ 98中出现的智能指针,也是最早被创造出来的智能指针。

原理:采用管理权转移的方法,当拷贝构造一个对象时,就会将管理权转交给新的对象。将原来的对象置空。(这一点可在后边的代码部分中体现出来,也可以打开监视窗口进行监控,这里就不做演示了)。

缺点:由于采用了管理权转移的方式,那么缺陷也随之而来,我们不能使用该智能指针去拷贝构造。如果拷贝构造后会将原来的对象置空,那么原来的对象将不能被赋值(虽然该方法解决了在析构的时候会被析构两次的缺点,但确产生了新的缺点,这里很像是浅拷贝)

注意:该智能指针存在很大缺陷所以在公司中不会让用,但是面试中会被经常问到

1.1 模拟实现部分

template<class T>
class Auto_Ptr
{
public:
	Auto_Ptr(T* ptr = nullptr)
		:_ptr(ptr)
	{}

	~Auto_Ptr()
	{
		if (_ptr)
			delete _ptr;          
	}

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

	T* operator->()
	{
		return _ptr;
	}
	Auto_Ptr(Auto_Ptr<T>& cp)
		:_ptr(cp._ptr)
	{
		cp._ptr = nullptr;
	}

	Auto_Ptr<T>& operator=(Auto_Ptr<T> ap)
	{
		if (this != &ap)
		{
			if (_ptr)
				delete _ptr;
			_ptr = ap._ptr;
			ap._ptr = nullptr;          //可以很明显看出原来的被置空
		}
		return *this;
	}
 private:
	T* _ptr;
};

 2.unique_ptr

该智能指针是在Boost库中(在C++ 11中引入了)

原理:为了避免auto_ptr出现的问题,该智能指针简单粗暴的直接不让进行拷贝构造和赋值。

缺点:不能进行拷贝构造

注意:在面试中如果要让写一个智能指针没有其他要求,最好写unique_ptr最容易实现

2.1模拟实现

template<class T>
class Unique_Ptr
{
	Unique_Ptr(T* ptr = nullptr)
	:_ptr(ptr)
	{}

	~Unique_Ptr()
	{
		if (_ptr)
			delete _ptr;           
	}

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

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

private:
    //C++ 98
	//Unique_Ptr(Unique_Ptr<T>& cp);
	//Unique_Ptr<T>& operator=(Unique_Ptr<T> ap);

	//C++ 11
	Unique_Ptr(Unique_Ptr<T>& cp) = delete;
	Unique_Ptr<T>& operator=(Unique_Ptr<T> ap) = delete;
	T* _ptr;

};

3.shared_ptr

该智能指针是在Boost库中(在C++ 11中引入了)

原理:是通过引用计数的方式来实现多个shared_ptr对象之间共享资源。例如:最后一个出宿舍的人必须将门锁了。

  • shared_ptr在其内部,给每个资源都维护了着一份计数,用来记录该份资源被几个对象
  • 在对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减
  • 如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源
  •  如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指针了

缺点:会有循环引用的问题,存在线程安全问题

3.1 图解原理

3.2 模拟实现

template<class T>
class Shared_Ptr
{
public:
	Shared_Ptr(T* ptr = nullptr)
		:_ptr(ptr)
		, pCount(new int(1))
	{
		if (_ptr == nullptr)
			*pCount = 1;
	}
	~Shared_Ptr()
	{
		if (_ptr && ((*pCount)--) == 0)
		{
			delete _ptr;
			delete pCount;
		}
	}

	Shared_Ptr(Shared_Ptr<T>& cp)
	{
		_ptr = cp._ptr;
		pCount = cp.pCount;
		if (_ptr)
		   ++(*pCount);
	}

	Shared_Ptr<T>& operator=(Shared_Ptr<T> ap)
	{
		if (_ptr != ap._ptr)
		{
			//释放旧资源
			if (_ptr && pCount == 0)
			{
				delete _ptr;
				delete pCount;
			}
			
			_ptr = ap._ptr;
			pCount = ap.pCount;

			if (_ptr)
				++(*pCount);
		}
		return *this;
	}

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

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

	int UseCount()
	{
		return *pCount;
	}
private:
	T* _ptr;
	int* pCount;
};

shared_ptr的线程安全问题和循环引用的解决方法下篇文章在做分享

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值