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

 

目录

​编辑

一.什么是智能指针

        1.RAII

        2.智能智能指针

二.为什么需要智能指针

        1.内存泄漏

               a. 什么是内存泄漏,内存泄漏的危害

                b.内存泄漏分类

                c.如何检测内存泄漏

                d.如何避免内存泄漏

                总结一下:

        2.为什么需要智能指针以及智能指针的原理

三.智能指针的使用

        1.C++98中的败笔智能指针auto_ptr

        2.C++11中的智能指针

                a.unique_ptr 不可拷贝的智能指针

                b.share_ptr 可以拷贝的智能指针        

        c.weak_ptr 用来解决share_ptr中的循环引用问题


 

一.什么智能指针

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

                 在程序创建一个专门管理在程序中申请资源的类,通过这个类管理我们申请的资源。

二.为什么需要智能指针

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

void MemoryLeaks()
{
   // 1.内存申请了忘记释放
  int* p1 = (int*)malloc(sizeof(int));
  int* p2 = new int;
  
  // 2.异常安全问题
  int* p3 = new int[10];
  
  Func(); // 这里Func函数异常导致 delete[] p3未执行,p3没被释放.
  
  delete[] p3;
}
                b.内存泄漏分类
                        C/C++程序中一般我们关心两种方面的内存泄漏:
                        堆内存泄漏(Heap leak)
                                堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一块内存,用完后必须通过调用相应的 free
或者
delete
删掉假设程序的设计错误导致这部分内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak
                        系统资源泄漏
                                指程序使用系统分配的资源,比方套接字文件描述符管道没有使用对应函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。
                c.如何检测内存泄漏
                        在linux下内存泄漏检测
linux
下几款内存泄漏检测工具
                        在windows下使用第三方工具
VLD
工具说明
                        其他工具
内存泄漏工具比较
                d.如何避免内存泄漏
                        1. 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。ps:这个理想状态。但是如果碰上异常时,就算注意释放了,还是可能会出问题需要一条智能指针来管理才有保证。
                        2. 采用RAII思想或者智能指针来管理资源
                    
                        3. 有些公司内部规范使用内部实现私有内存管理库。这套库自带内存泄漏检测功能选项
                        4. 出问题了使用内存泄漏工具检测。ps:不过很多工具都不够靠谱,或者收费昂贵。
                总结一下:
                        内存泄漏非常常见解决方案分为两种:1、事前预防型。如智能指针等。2
、事后查错型。如泄 漏检测工具
        2.为什么需要智能指针以及智能指针的原理
                

                  先来看这样一段代码
        

#include <iostream>
#include <string&gt;

using namespace std;

int main(void)
{
	string* str_ptr = new string;

	func();

	delete str_ptr;
	return 0;
}

                对于上面的代码,关于str_ptr中申请的堆中的资源,此时我们需要手动释放,那么当程序没有问题运行完成时,此时程序完成对我们申请的资源的释放,但是如果在中间的func()函数发生错误异常了,会改变我们程序的执行顺序,此时我们释放代码就不会被执行了。

                此时我们就会想如果有一个可以自己知道自己什么该死的空间就好了。

                此时就有人提出智能指针的概念了。

                通过一个类来管理我们申请的资源,该类的析构函数在类对象出作用域时候自动调用,会自动清理我们的资源。

template<class T&gt;
class SmartPtr {
public:
    SmartPtr(T* ptr = nullptr)
       : _ptr(ptr)
   {}
    ~SmartPtr()
   {
        if(_ptr)
            delete _ptr;
   }
    
private:
    T* _ptr;
};
int div()
{
   int a, b;
   cin &gt;&gt; a >> b;
   if (b == 0)
   throw invalid_argument("除0错误");
   return a / b;
}
void Func()
{
   ShardPtr<int> sp1(new int);
   ShardPtr<int> sp2(new int);
   cout << div() << endl;
}

int main()
{
    try {
 Func();
   }
    catch(const exception&amp; e)
   {
        cout<<e.what()<<endl;
   }
 return 0;
}

三.智能指针的使用

        
        1.C++98中的败笔智能指针auto_ptr
#include <memory>
#include <iostream>


using namespace std;

class A
{
public:
	A(int a)
		:_a(a)
	{
		cout << "A()" << endl;
	}

	~A()
	{
		cout << "~A()" << endl;
	}

private:

	int _a;
};

int main(void)
{
	auto_ptr<A> ap1(new A(1));
	auto_ptr<A> ap2(new A(2));
	auto_ptr<A> ap3;

	ap3 = ap1;

	return 0;
}

                此时我们发现这个auto_ptr在进行拷贝时候是转移资源的使用权,此后我们在使用ap1

这个智能指针的时候就无法使用了。

 

        2.C++11中的智能指针
                a.unique_ptr 不可拷贝的智能指针

                        

                   类的对象不可以进行拷贝两个方法

                          将该类的拷贝构造函数私有化。

                          unique_ptr(unique_ptr<T>&amp; up) = delete; 已删除函数

template<class T>
	class unique_ptr
	{
	public:
		// RAII
		// 像指针一样
		unique_ptr(T* ptr)
			:_ptr(ptr)
		{}

		~unique_ptr()
		{
			cout << "delete:" << _ptr << endl;
			delete _ptr;
		}

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

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

		// ap3(ap1)
		// 管理权转移
		// 防拷贝
		unique_ptr(unique_ptr<T>&amp; ap) = delete;
		unique_ptr<T>&amp; operator=(unique_ptr<T>&amp; ap) = delete;
	private:
		T* _ptr;
	};
                b.share_ptr 可以拷贝的智能指针        

                          

 

template<class T>
	class shared_ptr
	{
	public:
		// RAII
		// 像指针一样
		shared_ptr(T* ptr = nullptr)
			:_ptr(ptr)
			,_pcount(new int(1))
		{}

		// function<void(T*)> _del;
		template<class D>
		shared_ptr(T* ptr, D del)
			:_ptr(ptr)
			, _pcount(new int(1))
			, _del(del)
		{}

		~shared_ptr()
		{
			if (--(*_pcount) == 0)
			{
				cout << "delete:" << _ptr << endl;
				//delete _ptr;
				_del(_ptr);

				delete _pcount;
			}
		}

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

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

		// sp3(sp1)
		shared_ptr(const shared_ptr<T>&amp; sp)
			:_ptr(sp._ptr)
			,_pcount(sp._pcount)
		{
			++(*_pcount);
		}

		// sp1 = sp5
		// sp6 = sp6
		// sp4 = sp5
		shared_ptr<T>&amp; operator=(const shared_ptr<T>& sp)
		{
			if (_ptr == sp._ptr)
				return *this;

			if (--(*_pcount) == 0)
			{
				delete _ptr;
				delete _pcount;
			}

			_ptr = sp._ptr;
			_pcount = sp._pcount;
			++(*_pcount);

			return *this;
		}

		int use_count() const
		{
			return *_pcount;
		}

		T* get() const
		{
			return _ptr;
		}

	private:
		T* _ptr;
		int* _pcount;

		function<void(T*)> _del = [](T* ptr) {delete ptr; };
	};
        c.weak_ptr 用来解决share_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;
	};

四.定制删除

        上面的代码没法自动释放new到的多个空间

                

           解决方法
                

 

 

原文地址:https://blog.csdn.net/weixin_52159554/article/details/134740335

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_25756.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注