C++智能指针总结及模拟实现

1、为什么需要智能指针?

智能指针是一种预防型的内存泄漏的解决方案。智能指针在C++没 有垃圾回收器环境下,可以很好的解决异常安全等带来的内存泄漏问题。

2、什么是智能指针?

简单的来说就是设计一个类,让它能够具有指针的行为(重载 * 和 -> ),同时能够自主管理资源的申请与释放(体现在构造函数与析构函数);

以下为一个简单的只能指针的代码实现:

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

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

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

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

3、智能指针的分类

auto_ptr

>> 实现原理:由于上述简易智能指针存在浅拷贝问题,所以auto_ptr通过管理权的转移使多个多个对象虽然能够共用一份资源,但是只有一个对象能够对资源具有释放的权利。

>>缺点:当对象拷贝或者赋值后,前面的对象就悬空了

>>模拟实现:

template<class T>

class Auto_ptr {

public:
	Auto_ptr(T* ptr = nullptr)
		: _ptr(ptr)
	{}

	// 如果当前对象调用了拷贝构造函数就将Ap中_ptr赋给当前对象的_ptr
	Auto_ptr(Auto_ptr<T>& Ap)
		: _ptr(Ap._ptr)
	{
		Ap._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;
	}



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


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


	~Auto_ptr() {
		if (_ptr){
			delete _ptr;
		}
	}
private:
	T* _ptr;

};

unique_ptr

>> 实现原理:实现一份资源只能被一个对象占用(在auto_ptr的基础上禁用了拷贝构造函数与赋值运算符重载函数

>> 缺点:无法实现资源的共享

>>模拟实现:

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

	// 重载*
	T& operator*() {
		return *_ptr;
	}

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


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

	// C++98中实现方法为:将拷贝构造函数和赋值运算符重载函数的声明私有化,也可以protected化
private:
	Unique_ptr(Unique_ptr<T>& Up);
	Unique_ptr& operator=(Unique_ptr<T>& Up);


	// C++11中直接将拷贝构造函数和赋值运算符重载函数使用delete关键字删除

	Unique_ptr(Unique_ptr<T>& Up) = delete;
	Unique_ptr& operator=(Unique_ptr<T>& Up) = delete;

private:
	T* _ptr;
};

shared_ptr

>> 实现原理:通过引用计数实现多个对象共享一份资源,当有一个对象需要销毁时,资源计数就减1,若资源计数为了0就必须要释放资源

>> 缺点:

①不能实现对所有类型资源的释放;这个可以使用定制删除器解决,使用删除器时类似于使用仿函数

②线程安全问题:主要体现在两个方面:1)由于shared_ptr管理的资源是存放在堆上,当多个线程同时去访问同一份资源时可能会导致线程安全问题;2)由于引用计数是多个线程共享的,所以引用计数的++和--操作就是非原子性,可能会被操作多次,会导致资源问释放或者程序崩溃等线程安全问题;解决方法就是对引用计数的++和--操作加锁

③循环引用问题:主要体现在双向循环链表中,到两个节点连起来之后,data1的Sp1._ptr资源释放时候usecount-1,此时usecount为1,data1还不能被销毁,因为data2中的_pre还在使用data1的资源;data2的Sp2._ptr使用完毕之后usecount-1,此时也为1,data2也不能销毁,因为data1的pNext还在使用;这样就导致data1想销毁就得等data2的_pre离开,data2想要销毁就得等data1的pNext离开,双方僵持下来就导致了循环引用

>>模拟实现:已解决了线程安全问题

template<class T>
class Shared_ptr {
public:
	Shared_ptr(T* ptr = nullptr)
		: _ptr(ptr)
		, _pRefCount(new int(1))
		, _pMutex(new mutex)
	{}

	Shared_ptr(Shared_ptr<T>& Sp)
		: _ptr(Sp._ptr)
		, _pRefCount(Sp._pRefCount)
		, _pMutex(Sp._pMutex)
	{
		AddRefCount();
	}

	Shared_ptr<T>& operator(const Shared_ptr<T>& Sp) {
		if (_ptr != Sp._ptr) {
			// 释放旧资源
			Realse();

			// 共享新资源
			_ptr = Sp._ptr;
			_pRefCount = Sp._pRefCount;
			_pMutex = Sp._pMutex;

			// 资源计数+1
			AddRefCount();
		}

		return *this;
	}


	~Shared_ptr() {
		Realse();
	}

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

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

	// 需要对++操作进行加锁
	void AddRefCount() {
		_pMutex->lock();
		++(*_pRefCount);
		_pMutex->unlock();
	}

private:

	void Realse() {

		_pMutex->lock();
		// 当资源计数-1后为0释放资源
		if (--(*_pRefCount) == 0) {
			delete _ptr;
			delete _pRefCount;
		}
		_pMutex->unlock();

		if (_pMutex) {
			delete _pMutex;
		}

	}

	
private:
	T* _ptr;
	int* _pRefCount;
	mutex* _pMutex;

};

weak_ptr:weak_ptr主要就是用来与shared_ptr搭配使用解决循环引用的问题

>>实现原理,将data1和data2中的_pNext和_pre类型改为weak_ptr;当data1->_pNext = data2和data2->_pre = data1时不会增加data1和data2的资源计数

4、C++11中的智能指针与boost库中的智能指针的区别

boost库中的智能指针是C++11智能指针的原版,以下为智能指针的发展史

① C++ 98 中产生了第一个智能指针auto_ptr.

② C++ boost给出了更实用的scoped_ptr和shared_ptr和weak_ptr.

③C++ TR1,引入了shared_ptr等。不过注意的是TR1并不是标准版。

④C++ 11,引入了unique_ptr和shared_ptr和weak_ptr。需要注意的是unique_ptr对应boost的 scoped_ptr。并且这些智能指针的实现原理是参考boost中的实现的。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值