日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

RAII惯用法:C++资源管理的利器

發布時間:2023/12/20 c/c++ 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 RAII惯用法:C++资源管理的利器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

RAII是指C++語言中的一個慣用法(idiom),它是“Resource?Acquisition?Is?Initialization”的首字母縮寫。中文可將其翻譯為“資源獲取就是初始化”。雖然從某種程度上說這個名稱并沒有體現出該慣性法的本質精神,但是作為標準C++資源管理的關鍵技術,RAII早已在C++社群中深入人心。

我記得第一次學到RAII慣用法是在Bjarne Stroustrup的《C++程序設計語言(第3版)》一書中。當講述C++資源管理時,Bjarne這樣寫道:

使用局部對象管理資源的技術通常稱為“資源獲取就是初始化”。這種通用技術依賴于構造函數和析構函數的性質以及它們與異常處理的交互作用。

Bjarne這段話是什么意思呢?

首先讓我們來明確資源的概念,在計算機系統中,資源是數量有限且對系統正常運轉具有一定作用的元素。比如,內存,文件句柄,網絡套接字(network sockets),互斥鎖(mutex locks)等等,它們都屬于系統資源。由于資源的數量不是無限的,有的資源甚至在整個系統中僅有一份,因此我們在使用資源時必須嚴格遵循的步驟是:

1.?????????獲取資源

2.?????????使用資源

3.?????????釋放資源

例如在下面的UseFile函數中:

void UseFile(char const* fn)
{
????FILE* f = fopen(fn,?
"r");????????//?獲取資源
????//?
在此處使用文件句柄f...??????????//?使用資源
????fclose(f);???????????????????????//?
釋放資源
}

調用fopen()打開文件就是獲取文件句柄資源,操作完成之后,調用fclose()關閉文件就是釋放該資源。資源的釋放工作至關重要,如果只獲取而不釋放,那么資源最終會被耗盡。上面的代碼是否能夠保證在任何情況下都調用fclose函數呢?請考慮如下情況:

void UseFile(char const* fn)
{
????FILE* f = fopen(fn, "r");????????//?
獲取資源
????//?
使用資源
????if (!g()) return;????????????????//?
如果操作g失敗!
????// ...
????if (!h()) return;????????????????//?
如果操作h失敗!
????// ...
????fclose(f);???????????????????????//?
釋放資源
}

在使用文件f的過程中,因某些操作失敗而造成函數提前返回的現象經常出現。這時函數UseFile的執行流程將變為:


?

很明顯,這里忘記了一個重要的步驟:在操作gh失敗之后,UseFile函數必須首先調用fclose()關閉文件,然后才能返回其調用者,否則會造成資源泄漏。因此,需要將UseFile函數修改為:

void UseFile(char const* fn)
{
????FILE* f = fopen(fn, "r");????????//?
獲取資源
????//?
使用資源
????if (!g()) {?fclose(f);?return; }
????// ...
????if (!h()) {?fclose(f);?return; }
????// ...
????fclose(f);???????????????????????//?
釋放資源
}

現在的問題是:用于釋放資源的代碼fclose(f)需要在不同的位置重復書寫多次。如果再加入異常處理,情況會變得更加復雜。例如,在文件f的使用過程中,程序可能會拋出異常:

void UseFile(char const* fn)
{
????FILE* f = fopen(fn, "r");????????//?
獲取資源
????//?
使用資源
????try?{
????????if (!g()) { fclose(f); return; }
????????// ...
????????if (!h()) { fclose(f); return; }
????????// ...
????}
????catch?(...) {
????????fclose(f);???????????????????//?
釋放資源
????????throw;
????}
????fclose(f);???????????????????????//?
釋放資源
}

我們必須依靠catch(...)來捕獲所有的異常,關閉文件f,并重新拋出該異常。隨著控制流程復雜度的增加,需要添加資源釋放代碼的位置會越來越多。如果資源的數量還不止一個,那么程序員就更加難于招架了。可以想象這種做法的后果是:代碼臃腫,效率下降,更重要的是,程序的可理解性和可維護性明顯降低。是否存在一種方法可以實現資源管理的自動化呢?答案是肯定的。假設UseResources函數要用到n個資源,則進行資源管理的一般模式為:

void UseResources()
{
????//?
獲取資源1
????// ...
????//?
獲取資源n
????
????//?
使用這些資源
????
????//?
釋放資源n
????// ...
????//?
釋放資源1
}

不難看出資源管理技術的關鍵在于:要保證資源的釋放順序與獲取順序嚴格相反。這自然使我們聯想到局部對象的創建和銷毀過程。在C++中,定義在棧空間上的局部對象稱為自動存儲(automatic memory)對象。管理局部對象的任務非常簡單,因為它們的創建和銷毀工作是由系統自動完成的。我們只需在某個作用域(scope)中定義局部對象(這時系統自動調用構造函數以創建對象),然后就可以放心大膽地使用之,而不必擔心有關善后工作;當控制流程超出這個作用域的范圍時,系統會自動調用析構函數,從而銷毀該對象。

讀者可能會說:如果系統中的資源也具有如同局部對象一樣的特性,自動獲取,自動釋放,那該有多么美妙啊!。事實上,您的想法已經與RAII不謀而合了。既然類是C++中的主要抽象工具,那么就將資源抽象為類,用局部對象來表示資源,把管理資源的任務轉化為管理局部對象的任務。這就是RAII慣用法的真諦!可以毫不夸張地說,RAII有效地實現了C++資源管理的自動化。例如,我們可以將文件句柄FILE抽象為FileHandle類:

class FileHandle {
public:
????FileHandle(char const* n, char const* a) { p = fopen(n, a); }
????~FileHandle() { fclose(p); }
private:
????//?
禁止拷貝操作
????FileHandle(FileHandle const&);
????FileHandle& operator= (FileHandle const&);
????FILE *p;
};

FileHandle類的構造函數調用fopen()獲取資源;FileHandle類的析構函數調用fclose()釋放資源。請注意,考慮到FileHandle對象代表一種資源,它并不具有拷貝語義,因此我們將拷貝構造函數和賦值運算符聲明為私有成員。如果利用FileHandle類的局部對象表示文件句柄資源,那么前面的UseFile函數便可簡化為:

void UseFile(char const* fn)
{
????FileHandle file(fn,?
"r");?
????//?
在此處使用文件句柄f...
????//?
超出此作用域時,系統會自動調用file的析構函數,從而釋放資源
}

現在我們就不必擔心隱藏在代碼之中的return語句了;不管函數是正常結束,還是提前返回,系統都必須“乖乖地”調用f的析構函數,資源一定能被釋放。Bjarne所謂“使用局部對象管理資源的技術……依賴于構造函數和析構函數的性質”,說的正是這種情形。

且慢!如若使用文件file的代碼中有異常拋出,難道析構函數還會被調用嗎?此時RAII還能如此奏效嗎?問得好。事實上,當一個異常拋出之后,系統沿著函數調用棧,向上尋找catch子句的過程,稱為棧輾轉開解(stack unwinding)。C++標準規定,在輾轉開解函數調用棧的過程中,系統必須確保調用所有已創建起來的局部對象的析構函數。例如:

void Foo()
{
????FileHandle file1(
"n1.txt",?"r");?
????FileHandle file2(
"n2.txt",?"w");
????Bar();???????//?
可能拋出異常
????FileHandle file3(
"n3.txt",?"rw")
}

Foo()調用Bar()時,局部對象file1file2已經在Foo的函數調用棧中創建完畢,而file3卻尚未創建。如果Bar()拋出異常,那么file2file1的析構函數會被先后調用(注意:析構函數的調用順序與構造函數相反);由于此時棧中尚不存在file3對象,因此它的析構函數不會被調用。只有當一個對象的構造函數執行完畢之后,我們才認為該對象的創建工作已經完成。棧輾轉開解過程僅調用那些業已創建的對象的析構函數。

?

RAII慣用法同樣適用于需要管理多個資源的復雜對象。例如,Widget類的構造函數要獲取兩個資源:文件myFile和互斥鎖myLock。每個資源的獲取都有可能失敗并且拋出異常。為了正常使用Widget對象,這里我們必須維護一個不變式(invariant):當調用構造函數時,要么兩個資源全都獲得,對象創建成功;要么兩個資源都沒得到,對象創建失敗。獲取了文件而沒有得到互斥鎖的情況永遠不能出現,也就是說,不允許建立Widget對象的“半成品”。如果將RAII慣用法應用于成員對象,那么我們就可以實現這個不變式:

class Widget {
public:
????Widget(char const* myFile, char const* myLock)
????: file_(myFile),?????//?
獲取文件myFile
??????lock_(myLock)??????//?
獲取互斥鎖myLock
????{}
????// ...
private:
????FileHandle file_;
????LockHandle lock_;
};

FileHandleLockHandle類的對象作為Widget類的數據成員,分別表示需要獲取的文件和互斥鎖。資源的獲取過程就是兩個成員對象的初始化過程。在此系統會自動地為我們進行資源管理,程序員不必顯式地添加任何異常處理代碼。例如,當已經創建完file_,但尚未創建完lock_時,有一個異常被拋出,則系統會調用file_的析構函數,而不會調用lock_的析構函數。Bjarne所謂構造函數和析構函數與異常處理的交互作用”,說的就是這種情形。

綜上所述,RAII的本質內容是用對象代表資源,把管理資源的任務轉化為管理對象的任務,將資源的獲取和釋放與對象的構造和析構對應起來,從而確保在對象的生存期內資源始終有效,對象銷毀時資源必被釋放。換句話說,擁有對象就等于擁有資源,對象存在則資源必定存在。由此可見,RAII慣用法是進行資源管理的有力武器。C++程序員依靠RAII寫出的代碼不僅簡潔優雅,而且做到了異常安全。難怪微軟的MSDN雜志在最近的一篇文章中承認:“若論資源管理,誰也比不過標準C++”。


http://www.cnblogs.com/hsinwang/articles/214663.html

總結

以上是生活随笔為你收集整理的RAII惯用法:C++资源管理的利器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 亚洲欧美日韩网站 | 午夜性色| 在线观看精品视频 | 国产男人搡女人免费视频 | 波多野结衣在线影院 | 精品精品视频 | 亚洲色图美腿丝袜 | 亚洲一区二区三区黄色 | 亚洲制服丝袜av | 亚洲色图少妇 | 国产精品无码av在线有声小说 | av网站在线免费看 | 怨女1988国语版在线观看高清 | 性久久久久久久久久 | 丰满人妻一区二区三区53 | 国产91福利 | 91成人免费网站 | 久久视频热 | 亚洲成人精品在线 | 久久久久亚洲av成人毛片韩 | 青青草日韩 | 日韩在线综合 | 中文字幕资源网 | 最新视频 - 88av | 欧美色图在线观看 | 91资源在线视频 | 久久久国产免费 | caoprom在线视频 | 在线97| 日韩片在线观看 | 熟妇熟女乱妇乱女网站 | 一区二区三区啪啪啪 | 亚洲一区在线电影 | 精品久久无码视频 | 久久人| 麻豆视频免费在线 | 久久无码专区国产精品s | 美国免费高清电影在线观看 | 日韩一区二区三区视频在线 | 凹凸日日摸日日碰夜夜 | 国产黄色片免费看 | 亚洲欧美综合自拍 | 成人在线观看网址 | 欧美变态口味重另类 | 日本成人一区二区 | 一本之道高清无码视频 | 国产精品视频 | 美国三级视频 | 精品国产乱码久久久久久影片 | 亚洲图片综合区 | 91高清视频在线观看 | 欧美一级视频免费观看 | 精品国产99久久久久久 | 小视频在线播放 | 久久久久久久久久久网站 | 免费成人福利视频 | 欧美成人高清视频 | chinese麻豆新拍video | 亚洲福利一区二区三区 | 国产精品久久久久久 | 日韩伦理在线视频 | 牛牛影视一区二区三区 | 深爱激情综合网 | 久久久无码精品亚洲国产 | 无法忍受在线观看 | 在线麻豆av | 日韩h在线观看 | 久久av高潮av无av萌白 | 国产午夜成人久久无码一区二区 | 一级片在线视频 | 国产精品自拍视频 | 国产经典三级在线 | 国产高清不卡 | 乳女教师の诱惑julia | 天堂在线成人 | 最新欧美日韩 | 欧美区一区二 | 九热精品视频 | 欧洲高潮三级做爰 | 欧美第九页 | 9色视频 | 深夜精品 | 免费av视屏 | 佐山爱在线视频 | 青青操视频在线观看 | 久久午夜国产 | 成年人天堂 | 999福利视频 | 91一区二区三区在线观看 | 成人录像 | 九九爱精品视频 | wwwxxx日本免费| 成人网站在线进入爽爽爽 | 三度诱惑免费版电影在线观看 | 欧美精品国产一区 | 特级毛片www | 开心春色激情网 | 国产精品正在播放 | 日日鲁鲁鲁夜夜爽爽狠狠视频97 |