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