IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++ 智能指针 -> 正文阅读

[C++知识库]C++ 智能指针

内存泄漏

什么是内存泄漏:
内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。

内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等,出现内存泄漏会导致响应越来越慢,最终卡死。

内存泄漏的分类

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

如何避免内存泄漏

  1. 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。ps:是理想状态。但是如果碰上异常时,就算注意释放了,还是可能会出问题。需要智能指针来管理才有保证。
  2. 采用RAII思想或者智能指针来管理资源。
  3. 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。
  4. 出问题了使用内存泄漏工具检测。ps:不过很多工具都不够靠谱,或者收费昂贵。

    总结一下:
    内存泄漏非常常见,解决方案分为两种:
    1、事前预防型。如智能指针等。2、事后查错型。如泄漏检测工具

智能指针的使用及原理

RAII

RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。
对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。(智能指针/锁守卫:lock_guard,unique_lock)
这种做法有两大好处:
不需要显式地释放资源。采用这种方式,对象所需的资源在其生命期内始终保持有效。

#pragma once

template <class T>
class SmartPtr
{
public:
	SmartPtr(T* ptr)
		:_ptr(ptr)
	{}
	~SmartPtr()
	{
		cout << "delete# " << _ptr << endl;
		delete _ptr;
	}
private:
	T* _ptr;

};
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include "SmartPtr.h"
#
using namespace std;
int div()throw(invalid_argument)
{
	int a, b;
	cin >> a >> b;
	if (b == 0)
	{
		throw invalid_argument("除0错误");
		return a / b;
	}

}
void f1()
{
	int* p = new int;
	SmartPtr<int> Sp(p);
	cout << div() << endl;
	//delete p;
}
int main()
{
	try
	{
		f1();
	}
	catch (exception& e)
	{
		cout << e.what() << endl;
	}
	return 0;
}

在这里插入图片描述
智能指针的原理:
1、RAII特性
2、重载operator*和operator->,具有像指针一样的行为

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;

};

auto_ptr

auto_ptr的实现原理:管理权转移的思想,保证只有一个对象在管理资源同时导致拷贝后原对象悬空

namespace app
{
	template <class T>
	class auto_ptr
	{//C++98---管理权转移,保证只有一个对象在管理资源
	public:
		auto_ptr(T* ptr)
			:_ptr(ptr)
		{}
		~auto_ptr()
		{
			if (_ptr != nullptr)
			{
				cout << "delete# " << _ptr << endl;
				delete _ptr;
				_ptr == nullptr;
			}

		}
		//管理权转移
		//ap2(ap1)
		auto_ptr(auto_ptr<T>& ap)
			:_ptr(ap._ptr)
		{
			ap._ptr = nullptr;
		}
		//赋值
		//ap1 = ap3 ap1 = ap1
		auto_ptr<T>& operator=(auto_ptr<T>& ap)
		{
			if (this != &ap)
			{
				delete _ptr;
				_ptr = ap._ptr;
				ap._ptr = nullptr;
			}
			return *this;
		}
		//可以像指针一样使用
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;

	};
}

int main()
{
	app::auto_ptr<int> ap1(new int);//有拷贝问题
	app::auto_ptr<int> ap2(ap1);
	//*ap1 = 10;出错
	//*ap2 = 20;
	return 0;
}

在这里插入图片描述

unique_ptr

unique_ptr的实现原理:简单粗暴的防拷贝
boost中的scoped_ptr

namespace un
{
	template <class T>
	class unique_ptr
	{//简单粗暴的解决拷贝:禁止拷贝
	public:
		unique_ptr(T* ptr)
			:_ptr(ptr)
		{}
		~unique_ptr()
		{
			
				cout << "delete# " << _ptr << endl;
				delete _ptr;
			

		}

		//可以像指针一样使用
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
		unique_ptr(const unique_ptr<T>&) = delete;
		unique_ptr<T>operator=(const unique_ptr<T>&) = delete;
	private:
		T* _ptr;

	};
}

shared_ptr

shared_ptr的原理:是通过引用计数的方式来实现多个shared_ptr对象之间共享资源。
就是boost中的dhared_ptr—缺陷:循环引用

  • shared_ptr在其内部,给每个资源都维护了着一份计数,用来记录该份资源被几个对象共享。
  • 在对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减一。
  • 如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源;
  • 如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指针
template <class T>
	class shared_ptr
	{//简单粗暴的解决拷贝:禁止拷贝
	private:
		void Addref()
		{
			_mtx->lock();
			++(*_count);
			_mtx->unlock();
		}
		void Releaseref()
		{
			_mtx->lock();
			bool flag = false;
			if (--(*_count) == 0)
			{
				cout << "delete: " << _ptr << endl;
				delete _ptr;
				delete _count;
				flag = true;
			}
			_mtx->unlock();
			if (flag == true)
			{
				delete _mtx;
			}
		}
	public:
		shared_ptr(T* ptr)
			:_ptr(ptr)
			, _count(new int(1))
			, _mtx(new mutex)
		{}
		~shared_ptr()
		{
			Releaseref();
		}
		
		shared_ptr(const shared_ptr<T>& sp)
			:_ptr(sp._ptr)
			, _count(sp._count)
			, _mtx(sp._mtx)
		{
			Addref();
		}
		//sp1 = sp2 sp1 = sp1
		shared_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			if (_ptr != sp._ptr)
			{
				Releaseref();
				_count = sp._count;
				_ptr = sp._ptr;
				_mtx = sp._mtx;
				Addref();
			}
			return *this;
		}

		//可以像指针一样使用
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
		int use_count()
		{
			return *_count;
		}
	
	private:
		T* _ptr;
		int* _count;
		mutex* _mtx;//解决线程安全问题
	};

weak_ptr

就是boost中的weak_ptr主要用来解决shared_ptr的循环引用问题

template<class T>
	class weak_ptr
	{
		//不参加资源管理,不增加shared_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;
	};

删除器

解决不是new出来的对象通过智能指针管理

template<class T, class D = Delete<T>>
	class shared_ptr
	{
	private:
		void AddRef()
		{
			_pmutex->lock();
			++(*_pcount);
			_pmutex->unlock();
		}

		void ReleaseRef()
		{
			_pmutex->lock();
			bool flag = false;
			if (--(*_pcount) == 0)
			{
				if (_ptr)
				{
					cout << "delete:" << _ptr << endl;
					//delete _ptr;
					_del(_ptr);
				}

				delete _pcount;
				flag = true;
			}
			_pmutex->unlock();

			if (flag == true)
			{
				delete _pmutex;
			}
		}
	public:
		// RAII
		shared_ptr(T* ptr = nullptr)
			:_ptr(ptr)
			, _pcount(new int(1))
			, _pmutex(new mutex)
		{}

		shared_ptr(T* ptr, D del)
			: _ptr(ptr)
			, _pcount(new int(1))
			, _pmutex(new mutex)
			, _del(del)
		{}

		~shared_ptr()
		{
			ReleaseRef();
		}

		shared_ptr(const shared_ptr<T>& sp)
			:_ptr(sp._ptr)
			, _pcount(sp._pcount)
			, _pmutex(sp._pmutex)
		{
			AddRef();
		}

		// sp1 = sp1
		// sp1 = sp2
		// sp3 = sp1;
		shared_ptr<T>& operator=(const shared_ptr<T>& sp)
		{
			if (_ptr != sp._ptr)
			{
				ReleaseRef();

				_pcount = sp._pcount;
				_ptr = sp._ptr;
				_pmutex = sp._pmutex;

				AddRef();
			}

			return *this;
		}


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

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

		int use_count()
		{
			return *_pcount;
		}

		T* get() const
		{
			return _ptr;
		}
	private:
		T* _ptr;
		int* _pcount;
		mutex* _pmutex;
		D _del;
	};

定制删除器
	//定制删除器---删除器控制释放资源的方式
	template<class T>
	struct DelArr
	{
		void operator()(const T* ptr)
		{
			cout << "delete[]: " << ptr << endl;
			delete[] ptr;
		}		
	};
	// 定制删除器
template<class T>
class DelRef
{
public:
	void operator()(T*& ptr)
	{
		if (ptr)
		{
			delete ptr;
			ptr = nullptr;
		}
	}
};
 
template<class T>
class Free
{
public:
	void operator()(T*& ptr)
	{
		if (ptr)
		{
			free(ptr);
			ptr = nullptr;
		}
	}
};
 
class FClose
{
public:
	void operator()(FILE*& pf)
	{
		if (pf)
		{
			fclose(pf);
			pf = nullptr;
		}
	}
};
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-26 11:12:28  更:2022-02-26 11:14:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:03:02-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码