C 資源管理之 RAII

2021-09-07 11:30:38 字數 2730 閱讀 4193

raii,它是「r

esource acquisition is initialization」的首字母縮寫。也稱為「資源獲取就是初始化」,是c++等程式語言常用的管理資源、避免記憶體洩露的方法。它保證在任何情況下,使用物件時先構造物件,最後析構物件。

raii的好處在於它提供了一種資源自動管理的方式,當產生異常、回滾等現象時,raii可以正確地釋放掉資源。

當講述c++資源管理時,bjarne這樣寫道:

使用區域性物件管理資源的技術通常稱為「資源獲取就是初始化」。這種通用技術依賴於建構函式和析構函式的性質以及它們與異常處理的互動作用。

raii 技術:

我們在c++中經常使用new申請了記憶體空間,但是卻也經常忘記delete**申請的空間,容易造成記憶體溢位,於是raii技術就誕生了,來解決這樣的問題。

raii(resource acquisition is initialization)機制是bjarne stroustrup首先提出的,是一種利用物件生命週期來控制程式資源(如記憶體、檔案控制代碼、網路連線、互斥量等等)的簡單技術。

我們知道在函式內部的一些成員是放置在棧空間上的,當函式返回時,這些棧上的區域性變數就會立即釋放空間,於是bjarne stroustrup就想到確保能執行資源釋放**的地方就是在這個程式段(棧)中放置的物件的析構函式了,

因為stack winding會保證它們的析構函式都會被執行。raii就利用了棧裡面的變數的這一特點。

stack winding & unwinding

當程式執行時,每乙個函式(包括資料、暫存器、程式計數器,等等)在呼叫時,都被對映到棧上。這就是 stack winding。

unwinding 是以相反順序把函式從棧上移除的過程。

正常的 stack unwinding 發生在函式返回時;不正常的情況,比如引發異常,呼叫setjmplongjmp,也會導致 stack unwinding。

可見 stack unwinding 的過程中,區域性物件的析構函式將逐一被呼叫。這也就是 raii 工作的原理,它是由語言和編譯器來保證的。

raii 的一般做法是這樣的:在物件構造時獲取資源,接著控制對資源的訪問使之在物件的生命週期內始終保持有效,最後在物件析構的時候釋放資源。藉此,我們實際上把管理乙份資源的責任託管給了乙個存放在棧空間上的區域性物件。

這種做法有兩大好處: 

(1)不需要顯式地釋放資源。 

(2)採用這種方式,物件所需的資源在其生命期內始終保持有效。

首先讓我們來明確資源的概念,在計算機系統中,資源是數量有限且對系統正常運轉具有一定作用的元素。

比如,記憶體,檔案控制代碼,網路套接字(network sockets),互斥鎖(mutex locks)等等,它們都屬於系統資源。

由於資源的數量不是無限的,有的資源甚至在整個系統中僅有乙份,因此我們在使用資源時必須嚴格遵循的步驟是:

例子:

void func()  

... // 如果 在使用fp指標時產生異常 並退出

// 那麼 fp檔案就沒有正常關閉

fclose(fp);

}

在資源的獲取到釋放之間,我們往往需要使用資源,但常常一些不可預計的異常是在使用過程中產生,就會使資源的釋放環節沒有得到執行。

此時,就可以讓raii慣用法大顯身手了。

raii的實現原理很簡單,利用stack上的臨時物件生命期是程式自動管理的這一特點,將我們的資源釋放操作封裝在乙個臨時物件中。

具體示例**如下:

class resource{};  

class raii //獲取資源

~raii() //釋放資源

resource* get() //訪問資源

private:

resource* r_;

};

void useresources()

不難看出資源管理技術的關鍵在於:要保證資源的釋放順序與獲取順序嚴格相反。

這自然使我們聯想到區域性物件的建立和銷毀過程。在c++中,定義在棧空間上的區域性物件稱為自動儲存(automatic memory)物件。

管理區域性物件的任務非常簡單,因為它們的建立和銷毀工作是由系統自動完成的。

我們只需在某個作用域(scope)中定義區域性物件(這時系統自動呼叫建構函式以建立物件),然後就可以放心大膽地使用之,而不必擔心有關善後工作;當控制流程超出這個作用域的範圍時,系統會自動呼叫析構函式,從而銷毀該物件。

讀者可能會說:如果系統中的資源也具有如同區域性物件一樣的特性,自動獲取,自動釋放,那該有多麼美妙啊!。事實上,您的想法已經與raii不謀而合了。既然類是c++中的主要抽象工具,那麼就將資源抽象為類,用區域性物件來表示資源,把管理資源的任務轉化為管理區域性物件的任務。這就是raii慣用法的真諦!可以毫不誇張地說,raii有效地實現了c++資源管理的自動化。

綜上所述,raii的本質內容是用物件代表資源,把管理資源的任務轉化為管理物件的任務,將資源的獲取和釋放與物件的構造和析構對應起來,從而確保在物件的生存期內資源始終有效,物件銷毀時資源必被釋放。

換句話說,擁有物件就等於擁有資源,物件存在則資源必定存在。由此可見,raii慣用法是進行資源管理的有力**。c++程式設計師依靠raii寫出的**不僅簡潔優雅,而且做到了異常安全。

參考:

對RAII資源管理的理解

raii是c 語言中常見習慣用法,全稱為 resource acquisition is initialization 意為資源獲取就是初始化。通常用來管理物件記憶體資源,已經比如檔案描述符 互斥鎖等資源。raii基本原理就是使用區域性物件管理資源,依賴於建構函式和析構函式的性質以及它們與異常處理的...

RAII慣用法 C 資源管理的利器

raii是指c 語言中的乙個慣用法 idiom 它是 resourceacquisitionisinitialization 的首字母縮寫。中文可將其翻譯為 資源獲取就是初始化 雖然從某種程度上說這個名稱並沒有體現出該慣性法的本質精神,但是作為標準c 資源管理的關鍵技術,raii早已在c 社群中深入...

RAII慣用法 C 資源管理的利器

原文 raii是指c 語言中的乙個慣用法 idiom 它是 resource acquisition is initialization 的首字母縮寫。中文可將其翻譯為 資源獲取就是初始化 雖然從某種程度上說這個名稱並沒有體現出該慣性法的本質精神,但是作為標準c 資源管理的關鍵技術,raii早已在c...