c++ RAII机制

RAII 是 resource acquisition is initialization 的缩写,意为“资源获取即初始化”。它是 C++ 之父 Bjarne Stroustrup 提出的设计理念,其核心是把资源和对象的生命周期绑定,对象创建获取资源,对象销毁释放资源。在 RAII 的指导下,C++ 把底层的资源管理问题提升到了对象生命周期管理的更高层次。


那么到底什么是 RALL 机制?


使用 C++ 时,最让人头疼的便是内存管理,但却又正是对内存高度的可操作性给了 C++ 程序猿极大的自由与装逼资本。

当我们 new 出一块内存空间,在使用完之后,如果不使用 delete 来释放这块资源则将导致内存泄露,这在中大型项目中是极具破坏性的。但是人无完人,我们并不能保证每次都记得释放无法再次获取到不再使用的内存,下面我给出一个例子,大家看看忘记释放资源而造成内存泄露是多么恐怖!!

  1. #include <iostream>  
  2. #include <memory>  
  3.   
  4.   
  5. int main()  
  6. {  
  7.     for (int i = 1; i <= 10000000; i++)  
  8.     {  
  9.         int32_t *ptr = new int32_t[3];  
  10.         ptr[0] = 1;  
  11.         ptr[1] = 2;  
  12.         ptr[2] = 3;  
  13.         //delete ptr;     //假设忘记了释放内存  
  14.     }  
  15.     system("pause");  
  16.     return 0;  
  17. }  

运行程序,打开资源管理器,可以这么简单的一个程序竟然就已经占用了536.7MB的内存,所以大家应该祈祷千万不要犯这么低级的错误!



可是祈祷真的有用吗?作为一名程序猿,最好不要把自己的命运交给上帝,而应该扮演上帝的角色。

有没有什么方法能够保证资源的自动释放呢?就像JAVA一样,但是却又不失C++程序猿的面子。

这个时候我们想到对象的析构是自动完成的,那么可不可以利用这个机制呢?答案很明确,可以。我们需要做的便是将资源托管给某个对象,或者说这个对象是资源的代理,在这个对象析构的时候完成资源的释放。于是我们可以将上例改成如下形式:

扫描二维码关注公众号,回复: 62435 查看本文章
  1. #include <iostream>  
  2. #include <memory>  
  3.   
  4. template<typename T>  
  5. class auto_release_ptr  
  6. {  
  7. public:  
  8.     auto_release_ptr(T *t) :_t(t){};  
  9.     ~auto_release_ptr()  
  10.     {  
  11.         delete _t;  
  12.     };  
  13.   
  14.     T * getPtr()  
  15.     {  
  16.         return _t;  
  17.     }  
  18.   
  19. private:  
  20.     T *_t;  
  21. };  
  22.   
  23. int main()  
  24. {  
  25.     for (int i = 1; i <= 10000000; i++)  
  26.     {  
  27.         auto arp = auto_release_ptr<int32_t>(new int32_t[3]);  
  28.         int32_t *ptr = arp.getPtr();  
  29.         ptr[0] = 1;  
  30.         ptr[1] = 2;  
  31.         ptr[2] = 3;  
  32.     }  
  33.     system("pause");  
  34.     return 0;  
  35. }  

然后内存占用变成了这样:


太棒了,只用每次 new 的时候将其传给我们的模板类 auto_release_ptr 就可以防止内存泄露了!让我们来看看这是怎么实现的。

当我们使用 new 出一块内存的时候,我们将其传给了模板类 auto_release_ptr,再通过其实例的 getPtr() 方法得到了内存地址。auto_release_ptr 有一个数据成员在构造时完成了初始化并指向了 new 出来的空间,而在其析构函数中,我们使用 delete 来释放这块内存空间,于是我们 new 出来的资源便有了和 auto_release_ptr 对象一样的生命周期,并且会在其托管的 auto_release_ptr 对象生命周期结束时被释放。由于 ptr 与 auto_release_ptr  对象的定义是在一块的,所以它们的生命周期自然也是相同的,即便 ptr 被回收时我们也不用再担心其指向的内存空间没有被释放了。


当然,这里只是简单举个例子来说明RALL。RALL机制便是通过利用对象的自动销毁,使得资源也具有了生命周期,有了自动销毁(自动回收)的功能。

更多的如智能指针,lock_guard都利用了RALL机制来实现。

猜你喜欢

转载自blog.csdn.net/datase/article/details/80075143