簡(jiǎn)單介紹C++ RAII
在C語(yǔ)言中,資源管理是一個(gè)極為繁瑣易錯(cuò)的工作,大多復(fù)雜的C系統(tǒng)都面臨著內(nèi)存泄露、懸掛指針等問(wèn)題。這是一方面是由底層語(yǔ)言的特點(diǎn)決定;另一方面也是由于C語(yǔ)言特性相對(duì)較少,嚴(yán)重依賴程序員進(jìn)行正確的資源管理,缺乏有效的支持手段。
C#和C++兩門語(yǔ)言的定位不同,它們?cè)谫Y源管理方面采取了兩種截然不同的方式:一為GC,一為RAII。GC讓程序建立在更高的抽象層次上,使資源管理變得更方便,更安全;而C++ RAII則保留了C的底層能力,同時(shí)在C++特性的支持下提供了簡(jiǎn)單有效的資源管理方式。我們知道C++最激烈的批評(píng)往往來(lái)自于C社區(qū),而在我看來(lái)C程序員可以不接受虛函數(shù),不接受模板,但有什么理由不接受RAII呢?可以說(shuō)RAII是C++相對(duì)C來(lái)說(shuō)幾乎無(wú)副作用的明顯進(jìn)步。
C++ RAII
RAII是resource acquisition is initialization的縮寫,意為“資源獲取即初始化”。它是C++之父Bjarne Stroustrup提出的設(shè)計(jì)理念,其核心是把資源和對(duì)象的生命周期綁定,對(duì)象創(chuàng)建獲取資源,對(duì)象銷毀釋放資源。在RAII的指導(dǎo)下,C++把底層的資源管理問(wèn)題提升到了對(duì)象生命周期管理的更高層次。上面的例子,我們把new所獲取的內(nèi)存塊視為資源,把r對(duì)象視為資源的代理對(duì)象,r應(yīng)負(fù)責(zé)資源的獲取和釋放。在棧語(yǔ)義和操作符重載的支持下,C++ RAII體現(xiàn)出了簡(jiǎn)潔、安全、實(shí)時(shí)的特點(diǎn):
1.概念簡(jiǎn)潔性:讓資源(包括內(nèi)存和非內(nèi)存資源)和對(duì)象的生命周期綁定,資源類的設(shè)計(jì)者只需用在類定義內(nèi)部處理資源問(wèn)題,提高了程序的可維護(hù)性
2.類型安全性:通過(guò)資源代理對(duì)象包裝資源(指針變量),并利用運(yùn)算符重載提供指針運(yùn)算方便使用,但對(duì)外暴露類型安全的接口
3.異常安全性:棧語(yǔ)義保證對(duì)象析構(gòu)函數(shù)的調(diào)用,提高了程序的健壯性
4.釋放實(shí)時(shí)性:和GC相比,RAII達(dá)到了和手動(dòng)釋放資源一樣的實(shí)時(shí)性,因此可以承擔(dān)底層開發(fā)的重任
也許你還在驚訝RAII如此簡(jiǎn)單的時(shí)候,關(guān)于RAII的主要內(nèi)容已經(jīng)介紹完了。簡(jiǎn)單不意味著簡(jiǎn)陋,在我看來(lái)RAII雖然不像GC一樣,是一套具體的機(jī)制,但它蘊(yùn)含的對(duì)象與資源關(guān)系的哲學(xué)深度的理解卻使得我對(duì)Bjarne Stroustrup肅然起敬!
最后,不得不提醒RAII的理念固然簡(jiǎn)單,不過(guò)在具體實(shí)現(xiàn)的時(shí)候仍有需要小心的地方。比如對(duì)于STL的auto_ptr,可以視為資源的代理對(duì)象,auto_ptr對(duì)象間的賦值是一個(gè)需要特別注意的地方。簡(jiǎn)單說(shuō)來(lái)資源代理對(duì)象間賦值的語(yǔ)義不滿足“賦值相等”,其語(yǔ)義是資源管理權(quán)的轉(zhuǎn)移。
什么是“賦值相等”呢?比如:
- int a;
- int b = 10;
- a = b; //這句話執(zhí)行后 a == b
但對(duì)于資源代理對(duì)象,這是不滿足的,比如:
- auto_ptr<int> a(null);
- auto_ptr<int> b(new int(123));
- a = b; //這句話執(zhí)行后a != b,賦值的語(yǔ)義是b把資源的管理權(quán)交給了a
【編輯推薦】