RAII详解

RAII详解什么是 RAII RAII 是 ResourceAcqu wiki 上面翻译成 资源获取就是初始化 的简称 是 C 语言的一种管理资源 避免泄漏的惯用法 利用的就是 C 构造的对象最终会被销毁的原则 RAII 的做法是使用一个对象 在其构造时获取对应的资源 在对象生命期内控制对资源的访问 使之始终保持有效 最后在对象析构的时候 释放构造时获取的资源 为什么要使用 RAII 上面说到 RAII 是用来管理资源 避免资源泄漏的方法 那么 用了这么久了 也写了这

什么是RAII?

RAII是Resource Acquisition Is Initialization(wiki上面翻译成 “资源获取就是初始化”)的简称,是C++语言的一种管理资源、避免泄漏的惯用法。利用的就是C++构造的对象最终会被销毁的原则。RAII的做法是使用一个对象,在其构造时获取对应的资源,在对象生命期内控制对资源的访问,使之始终保持有效,最后在对象析构的时候,释放构造时获取的资源。

为什么要使用RAII?

上面说到RAII是用来管理资源、避免资源泄漏的方法。那么,用了这么久了,也写了这么多程序了,口头上经常会说资源,那么资源是如何定义的?在计算机系统中,资源是数量有限且对系统正常运行具有一定作用的元素。比如:网络套接字、互斥锁、文件句柄和内存等等,它们属于系统资源。由于系统的资源是有限的,就好比自然界的石油,铁矿一样,不是取之不尽,用之不竭的,所以,我们在编程使用系统资源时,都必须遵循一个步骤:
1 申请资源;
2 使用资源;
3 释放资源。
第一步和第三步缺一不可,因为资源必须要申请才能使用的,使用完成以后,必须要释放,如果不释放的话,就会造成资源泄漏。








一个最简单的例子:

  
  1. #include

  2.  
  3. using namespace std;
  4.  
  5. int main()
  6.  
  7. {
  8. int *testArray = new int [10];
  9. // Here, you can use the array
  10. delete [] testArray;
  11. testArray = NULL ;
  12. return 0;
  13. }

小结:
但是如果程序很复杂的时候,需要为所有的new 分配的内存delete掉,导致极度臃肿,效率下降,更可怕的是,程序的可理解性和可维护性明显降低了,当操作增多时,处理资源释放的代码就会越来越多,越来越乱。如果某一个操作发生了异常而导致释放资源的语句没有被调用,怎么办?这个时候,RAII机制就可以派上用场了。

如何使用RAII?

当我们在一个函数内部使用局部变量,当退出了这个局部变量的作用域时,这个变量也就别销毁了;当这个变量是类对象时,这个时候,就会自动调用这个类的析构函数,而这一切都是自动发生的,不要程序员显示的去调用完成。这个也太好了,RAII就是这样去完成的。

由于系统的资源不具有自动释放的功能,而C++中的类具有自动调用析构函数的功能。如果把资源用类进行封装起来,对资源操作都封装在类的内部,在析构函数中进行释放资源。当定义的局部变量的生命结束时,它的析构函数就会自动的被调用,如此,就不用程序员显示的去调用释放资源的操作了。

使用RAII 机制的代码:

  
  1. #include

  2. using namespace std;
  3.  
  4. class ArrayOperation
  5. {
  6. public :
  7. ArrayOperation()
  8. {
  9. m_Array = new int [10];
  10. }
  11.  
  12. void InitArray()
  13. {
  14. for (int i = 0; i < 10; ++i)
  15. {
  16. *(m_Array + i) = i;
  17. }
  18. }
  19.  
  20. void ShowArray()
  21. {
  22. for (int i = 0; i <10; ++i)
  23. {
  24. cout<
  25. }
  26. }
  27.  
  28. ~ArrayOperation()
  29. {
  30. cout<< "~ArrayOperation is called" <
  31. if (m_Array != NULL )
  32. {
  33. delete[] m_Array;
  34. m_Array = NULL ;
  35. }
  36. }
  37.  
  38. private :
  39. int *m_Array;
  40. };
  41.  
  42. bool OperationA();
  43. bool OperationB();
  44.  
  45. int main()
  46. {
  47. ArrayOperation arrayOp;
  48. arrayOp.InitArray();
  49. arrayOp.ShowArray();
  50. return 0;
  51. }

上面这个例子没有多大的实际意义,只是为了说明RAII的机制问题。下面说一个具有实际意义的例子:

  
  1. template
  2. class lock_guard
  3. { // class with destructor that unlocks mutexes
  4. public:
  5. explicit lock_guard(_Mutexes&... _Mtxes)
  6. : _MyMutexes(_Mtxes...)
  7. { // construct and lock
  8. _STD lock(_Mtxes...);
  9. }
  10.  
  11. lock_guard(_Mutexes&... _Mtxes, adopt_lock_t)
  12. : _MyMutexes(_Mtxes...)
  13. { // construct but don't lock
  14. }
  15.  
  16. ~lock_guard() _NOEXCEPT
  17. { // unlock all
  18. _For_each_tuple_element(
  19. _MyMutexes,
  20. [](auto& _Mutex) _NOEXCEPT { _Mutex.unlock(); });
  21. }
  22.  
  23. lock_guard(const lock_guard&) = delete;
  24. lock_guard& operator=(const lock_guard&) = delete;
  25. private:
  26. tuple<_Mutexes&...> _MyMutexes;
  27. };

在使用多线程时,经常会涉及到共享数据的问题,C++中通过实例化std::mutex创建互斥量,通过调用成员函数lock()进行上锁,unlock()进行解锁。不过这意味着必须记住在每个函数出口都要去调用unlock(),也包括异常的情况,这非常麻烦,而且不易管理。C++标准库为互斥量提供了一个RAII语法的模板类std::lock_guard,其会在构造函数的时候提供已锁的互斥量,并在析构的时候进行解锁,从而保证了一个已锁的互斥量总是会被正确的解锁。上面的代码正式

>头文件中的源码,其中还使用到很多C++11的特性,比如delete/noexcept等,有兴趣的同学可以查一下。

文章参考:https://www.jianshu.com/p/b7ffe79498be

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/229806.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月16日 下午3:50
下一篇 2026年3月16日 下午3:50


相关推荐

  • mysql 左连接 自连接 例子

    mysql 左连接 自连接 例子连接就是将两个表按照某个公共字段来拼成一个大表。左连接就是在做连接是以左边这个表为标准,来遍历右边的表。例子:用户访问记录:问题:查出看了湖南卫视但没有看北京卫视的用户信息逻辑:先通过左连接将看了湖南卫视和北京卫视的查出来,然后再将看了湖南卫视但不在刚才查出的结果中的用户查出来。SELECT*FROMtest_visitWHEREchannel=’

    2022年5月28日
    31
  • idea20212.13激活_最新在线免费激活「建议收藏」

    (idea20212.13激活)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html0BXA05X8YC-eyJsaWN…

    2022年3月30日
    61
  • TIMEWAIT状态「建议收藏」

    TIMEWAIT状态「建议收藏」TIMEWAIT是友好的修改内核参数/proc/sys/net/ipv4/tcp_tw_recycle来快速回收被关闭的socket,使得TCP连接根本就不进入TIME_WAIT状态客户端在接收到服务器发送的FIN段后,没有立即进入CLOSED状态,而是进入TIME_WAIT状态;在TIME_WAIT状态,客户端连接要等待一段长为2MSL的时间才能完全关闭。TIME_WAIT状态存在的原因有…

    2022年5月1日
    40
  • Kimi开源轻量级中间件checkpoint-engine:能20秒内更新万亿参数模型? – 教程

    Kimi开源轻量级中间件checkpoint-engine:能20秒内更新万亿参数模型? – 教程

    2026年3月12日
    3
  • redis学习笔记(14)—redis基本命令总结

    redis学习笔记(14)—redis基本命令总结

    2021年10月10日
    45
  • golang deepcopy_dos copy命令拷贝文件夹

    golang deepcopy_dos copy命令拷贝文件夹Go语言中所有赋值操作都是值传递,如果结构中不含指针,则直接赋值就是深度拷贝;如果结构中含有指针(包括自定义指针,以及切片,map等使用了指针的内置类型),则数据源和拷贝之间对应指针会共同指向同一块内存,这时深度拷贝需要特别处理。目前,有三种方法,一是用gob序列化成字节序列再反序列化生成克隆对象;二是先转换成json字节序列,再解析字节序列生成克隆对象;三是针对具体情况,定制化拷贝。前两种方法虽……

    2025年6月18日
    4

发表回复

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

关注全栈程序员社区公众号