RAII 是 resource acquisition is initialization 的縮寫,意為“資源擷取即初始化”。它是 C++ 之父 Bjarne Stroustrup 提出的設計理念,其核心是把資源和對象的生命周期綁定,對象建立擷取資源,對象銷毀釋放資源。在 RAII 的指導下,C++ 把底層的資源管理問題提升到了對象生命周期管理的更高層次。
那麼到底什麼是 RALL 機制?
使用 C++ 時,最讓人頭疼的便是記憶體管理,但卻又正是對記憶體高度的可操作性給了 C++ 程式猿極大的自由與裝逼資本。
當我們 new 出一塊記憶體空間,在使用完之後,如果不使用 delete 來釋放這塊資源則将導緻記憶體洩露,這在中大型項目中是極具破壞性的。但是人無完人,我們并不能保證每次都記得釋放無法再次擷取到且不再使用的記憶體,下面我給出一個例子,大家看看忘記釋放資源而造成記憶體洩露是多麼恐怖!!
#include <iostream>
#include <memory>
int main()
{
for (int i = 1; i <= 10000000; i++)
{
int32_t *ptr = new int32_t[3];
ptr[0] = 1;
ptr[1] = 2;
ptr[2] = 3;
//delete ptr; //假設忘記了釋放記憶體
}
system("pause");
return 0;
}
運作程式,打開資料總管,可以這麼簡單的一個程式竟然就已經占用了536.7MB的記憶體,是以大家千萬不要犯這麼低級的錯誤!

有沒有什麼方法能夠保證資源的自動釋放呢?就像JAVA一樣,但是卻又不失C++程式猿的面子。
這個時候我們想到對象的析構是自動完成的,那麼可不可以利用這個機制呢?答案很明确,可以。我們需要做的便是将資源托管給某個對象,或者說這個對象是資源的代理,在這個對象析構的時候完成資源的釋放。于是我們可以将上例改成如下形式:
#include <iostream>
#include <memory>
template<typename T>
class auto_release_ptr
{
public:
auto_release_ptr(T *t) :_t(t){};
~auto_release_ptr()
{
delete _t;
};
T * getPtr()
{
return _t;
}
private:
T *_t;
};
int main()
{
for (int i = 1; i <= 10000000; i++)
{
auto arp = auto_release_ptr<int32_t>(new int32_t[3]);
int32_t *ptr = arp.getPtr();
ptr[0] = 1;
ptr[1] = 2;
ptr[2] = 3;
}
system("pause");
return 0;
}
然後記憶體占用變成了這樣:
太棒了,隻用每次 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機制來實作。