C++中的RAII介紹

來源:互聯網
上載者:User

標籤:color   guard   釋放   class   之間   標準   異常   initial   har   

摘要

RAII技術被認為是C++中管理資源的最佳方法,進一步引申,使用RAII技術也可以實現安全、簡潔的狀態管理,編寫出優雅的異常安全的代碼。

資源管理

RAII是C++的發明者Bjarne Stroustrup提出的概念,RAII全稱是“Resource Acquisition is Initialization”,直譯過來是“資源擷取即初始化”,也就是說在建構函式中申請分配資源,在解構函式中釋放資源。因為C++的語言機制保證了,當一個對象建立的時候,自動調用建構函式,當對象超出範圍的時候會自動調用解構函式。所以,在RAII的指導下,我們應該使用類來管理資源,將資源和對象的生命週期綁定。

智能指標(std::shared_ptr和std::unique_ptr)即RAII最具代表的實現,使用智能指標,可以實現自動的記憶體管理,再也不需要擔心忘記delete造成的記憶體流失。毫不誇張的來講,有了智能指標,代碼中幾乎不需要再出現delete了。

記憶體只是資源的一種,在這裡我們討論一下更加廣義的資源管理。比如說檔案的開啟與關閉、windows中控制代碼的擷取與釋放等等。按照常規的RAII技術需要寫一堆管理它們的類,有的時候顯得比較麻煩。但是如果手動釋放,通常還要考慮各種異常處理,比如說:

void function(){    FILE *f = fopen("test.txt", ‘r‘);    if (.....)    {        fclose(f);        return;    }    else if(.....)    {        fclose(f);        return;    }    fclose(f);    ......}

這裡介紹一個網上實現的我認為比較簡潔的方法,文章在這裡。作者使用了C++11標準中的lambda運算式和std::function相結合的方法,非常簡潔、明了。直接看代碼吧:

#define SCOPEGUARD_LINENAME_CAT(name, line) name##line#define SCOPEGUARD_LINENAME(name, line) SCOPEGUARD_LINENAME_CAT(name, line)#define ON_SCOPE_EXIT(callback) ScopeGuard SCOPEGUARD_LINENAME(EXIT, __LINE__)(callback)class ScopeGuard{public:    explicit ScopeGuard(std::function<void()> f) :         handle_exit_scope_(f){};    ~ScopeGuard(){ handle_exit_scope_(); }private:    std::function<void()> handle_exit_scope_;};int main(){    {        A *a = new A();        ON_SCOPE_EXIT([&] {delete a; });        ......    }    {        std::ofstream f("test.txt");        ON_SCOPE_EXIT([&] {f.close(); });        ......    }    system("pause");    return 0;}

作者為了使用方便,還定義了根據行號來對ScopeGuard類型對象命名的宏定義。看到了吧,當ScopeGuard對象超出範圍,ScopeGuard的解構函式中會調用handle_exit_scope_函數,也就是lambda運算式中的內容,所以在lamabda運算式中填上資源釋放的代碼即可,多麼簡潔、明了。既不需要為每種資源管理單獨寫對應的管理類,也不需要考慮手動釋放出現各種異常情況下的處理,同時資源的申請和釋放放在一起去寫,永遠不會忘記。

狀態管理

RAII另一個引申的應用是可以實現安全的狀態管理。一個典型的應用就是線上程同步中,使用std::unique_lock或者std::lock_guard對互斥量std:: mutex進行狀態管理。通常我們不會寫出如下的代碼:

std::mutex mutex_;void function(){    mutex_.lock();    ......    ......    mutex_.unlock();}

因為,在互斥量lock和unlock之間的代碼很可能會出現異常,或者有return語句,這樣的話,互斥量就不會正確的unlock,會導致線程的死結。所以正確的方式是使用std::unique_lock或者std::lock_guard對互斥量進行狀態管理:

std::mutex mutex_;void function(){    std::lock_guard<std::mutex> lock(mutex_);    ......    ......}

在建立std::lock_guard對象的時候,會對std::mutex對象進行lock,當std::lock_guard對象在超出範圍時,會自動std::mutex對象進行解鎖,這樣的話,就不用擔心代碼異常造成的線程死結。

總結

通過上面的分析可以看出,RAII的核心思想是將資源或者狀態與對象的生命週期綁定,通過C++的語言機制,實現資源和狀態的安全管理。理解和使用RAII能使軟體設計更清晰,代碼更健壯。

參考

1、http://mindhacks.cn/2012/08/27/modern-cpp-practices/

2、http://www.jellythink.com/archives/101

3、http://www.cppblog.com/aaxron/archive/2011/03/22/142475.html

C++中的RAII介紹

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.