RAII與Pimpl

RAII是Bjarne Stroustrup教授用於解決資源分配而發明的技術,資源獲取即初始化。

RAII是C++的構造機制的直接使用,即利用構造函數分配資源,利用析構函數來回收資源。

我們知道,在C/C++語言中,對動態分配的內存的處理必須十分謹慎。在沒有RAII應用的情況下,如果在內存釋放之前就離開指針的作用域,這時候幾乎沒機會去釋放該內存,除非垃圾回收器對其管制,否則我們要面對的將會是內存泄漏。

舉個例子來說明下RAII在內存分配方面的使用。

這是典型的C風格代碼,沒有應用RAII。
因此值得注意的是,destroy_bytearray必須在退出作用域前被調用。
然而在複雜的邏輯設計中,程序員往往要花大量的精力以確認所有在該作用域分配的ByteArray得到正確的釋放。

相形之下,C++運行機制保證了棧上對象一旦即將離開作用域,其析構函數將被執行,給予了釋放資源的時間。注意,在堆分配的對象必須調用delete來結束其生命。

C++11 STL中的std::unique_ptr可用於控制作用域中的動態分配的對象。
譬如:

函數bar()只是增加了一行,但強壯了很多,函數bar()執行完或者有異常拋出時,holder總會被析構,從而ba或被delete。

下面是ByteArray的Ada實現:

– 輸出如下
./main
Create
Initialize
Finalize
Finalize

另一種情況是對I/O資源的處理,當我們不再使用資源時,必須將資源歸還給系統。
下面例子來自 wikipedia的RAII條目

在write_to_file函數中,RAII作用於std::ofstream和std::lock_guard,從而保證了函數write_to_file在返回時,lock和file總會調用自身的析構函數,對於lock而言,它會釋放mutex,而file則會close。

Pimpl

 

Pimpl(pointer to implementation),是一種應用十分廣泛的技術,它的別名也很多,如Opaque pointer, handle classes等。

wikipedia上已經對其就Ada、C和C++舉例,這裏不作舉例。
個人認爲,Pimpl是RAII的延展,籍由RAII對資源的控制,把具體的數據佈局和實現從調用者視線內移開,從而簡化了API接口,也使得ABI兼容變得有可能,Qt和KDE正是使用Pimpl來維護ABI的一致性,另外也爲惰性初始化提供途徑,以及隱式共享提供了基礎。

我在設計代碼時也會考慮使用Pimpl,但不是必然使用,因爲Pimpl也會帶來副作用,主要有兩方面

  • Pimpl指針導致內存空間開銷增大
  • 類型間Pimpl的訪問需要較多間接的指針跳轉,甚至還用使用friend''來提升訪問權限,如以下代碼中,Teacher可以訪問Student的Context。

     

儘管如此,我個人還是在面向開發應用的接口中會盡量使用Pimpl來維護API和ABI的一致性,除非Pimpl會引起顯著的性能下降。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章