c++智能指针

目录

知识铺垫

内存泄漏

什么是内存泄露,和它的危害

内存泄露的分类

解决方案

RAII

智能指针

原理

std::unique_ptr

std::shared_ptr

std::weak_ptr

shared_ptr存在的问题


知识铺垫

在介绍智能指针之前我们先了解一下内存泄漏

内存泄漏

什么是内存泄露,和它的危害

  • 什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内 存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对 该段内存的控制,因而造成了内存的浪费。
  • 内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现 内存泄漏会导致响应越来越慢,最终卡死。

内存泄露的分类

  • 堆内存泄漏(Heap leak) :堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一 块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分 内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。
  • 系统资源泄漏: 指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。

解决方案

  • 事前预防型。如智能指针等。
  • 事后查错型。如泄漏检测工具。

RAII

RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源的简单技术。 在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。

上代码

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


class LockGuard
{
private:
    pthread_mutex_t* _mutex;
public:
    LockGuard(pthread_mutex_t* mutex);
    ~LockGuard();
};

LockGuard::LockGuard(pthread_mutex_t* mutex):_mutex(mutex)
{
    pthread_mutex_lock(_mutex);
}

LockGuard::~LockGuard()
{
    pthread_mutex_unlock(_mutex);
}
 

智能指针

原理

智能指针·= RAII + 重载operator*和opertaor->

下边就可以成为智能指针

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;
};

std::unique_ptr

unique_ptr文档

unique_ptr的实现原理:简单粗暴的防拷贝,下面简化模拟实现了一份UniquePtr来了解它的原理

template<class T>
class unique_ptr
{
public:
	unique_ptr(T* ptr)
		:_ptr(ptr)
	{}
	~unique_ptr()
	{
		if (_ptr)
		{
			cout << "delete:" << _ptr << endl;
			delete _ptr;
		}
	}
	// 像指针一样使用
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
	unique_ptr(const unique_ptr<T>& sp) = delete;
	unique_ptr<T>& operator=(const unique_ptr<T>& sp) = delete;
private:
	T* _ptr;
};

std::shared_ptr

shared_ptr文档

shared_ptr的原理:是通过引用计数的方式来实现多个shared_ptr对象之间共享资源。下面简化模拟实现了一份shared_ptr来了解它的原理

template<class T>
class shared_ptr
{
public:
	shared_ptr(T* ptr = nullptr)
		:_ptr(ptr)
		, _pRefCount(new int(1))
		, _pmtx(new mutex)
	{}
	shared_ptr(const shared_ptr<T>& sp)
		:_ptr(sp._ptr)
		, _pRefCount(sp._pRefCount)
		, _pmtx(sp._pmtx)
	{
		AddRef();
	}
	void Release()
	{
		_pmtx->lock();
		bool flag = false;
		if (--(*_pRefCount) == 0 && _ptr)
		{
			cout << "delete:" << _ptr << endl;
			delete _ptr;
			delete _pRefCount;
			flag = true;
		}
		_pmtx->unlock();
		if (flag == true)
		{
			delete _pmtx;
		}
	}
	void AddRef()
	{
		_pmtx->lock();
		++(*_pRefCount);
		_pmtx->unlock();
	}
	shared_ptr<T>& operator=(const shared_ptr<T>& sp)
	{
		//if (this != &sp)
		if (_ptr != sp._ptr)
		{
			Release();
			_ptr = sp._ptr;
			_pRefCount = sp._pRefCount;
			_pmtx = sp._pmtx;
			AddRef();
		}
		return *this;
	}
	int use_count()
	{
		return *_pRefCount;
	}
	~shared_ptr()
	{
		Release();
	}
	// 像指针一样使用
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
	T* get() const
	{
		return _ptr;
	}
private:
	T* _ptr;
	int* _pRefCount;
	mutex* _pmtx;
};

std::weak_ptr

]weak_ptr文档

简单模拟实现一下,了解一下原理

template<class T>
class weak_ptr
{
public:
	weak_ptr()
		:_ptr(nullptr)
	{}
	weak_ptr(const shared_ptr<T>& sp)
		:_ptr(sp.get())
	{}
	weak_ptr<T>& operator=(const shared_ptr<T>& sp)
	{
		_ptr = sp.get();
		return *this;
	}
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
private:
	T* _ptr;
};

shared_ptr存在的问题

std::shared_ptr的循环引用

struct ListNode
{
 int _data;
 shared_ptr<ListNode> _prev;
 shared_ptr<ListNode> _next;
 ~ListNode(){ cout << "~ListNode()" << endl; }
};
int main()
{
 shared_ptr<ListNode> node1(new ListNode);
 shared_ptr<ListNode> node2(new ListNode);
 cout << node1.use_count() << endl;
 cout << node2.use_count() << endl;
 node1->_next = node2;
 node2->_prev = node1;
 cout << node1.use_count() << endl;
 cout << node2.use_count() << endl;
 return 0;
}

最后谁也不会被释放。这时我们就需要weak_ptr

struct ListNode
{
	int _data;
	weak_ptr<ListNode> _prev;
	weak_ptr<ListNode> _next;
	~ListNode() { cout << "~ListNode()" << endl; }
};
int main()
{
	shared_ptr<ListNode> node1(new ListNode);
	shared_ptr<ListNode> node2(new ListNode);
	cout << node1.use_count() << endl;
	cout << node2.use_count() << endl;
	node1->_next = node2;
	node2->_prev = node1;
	cout << node1.use_count() << endl;
	cout << node2.use_count() << endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值