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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人工智能 > ChatGpt >内容正文

ChatGpt

用RAII技术管理资源及其泛型实现

發(fā)布時間:2023/12/2 ChatGpt 59 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用RAII技术管理资源及其泛型实现 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

RAII的含義是“資源獲取即初始化”。

一段看似安全的代碼

首先看一段代碼:

  • try{
  • int *p = new int[100];
  • // ... do something
  • delete[] p;
  • }catch(exception &e){
  • // .....
  • }
  • 這段代碼中,我們先進行了動態(tài)內(nèi)存分配,使用完釋放,看起來很完美,但是這段程序是否真的保證不會發(fā)生內(nèi)存泄漏?

    考慮這樣一種情形,程序在使用這段內(nèi)存的過程中throw一個異常,于是程序轉(zhuǎn)向catch塊,然后XXX。 這段內(nèi)存被釋放了嗎? 顯然沒有。 那么這段程序應(yīng)該從哪里改進呢?

    對象的生命期

    考慮一個問題:C++中對象的聲明期是怎樣的?在C++中,對象創(chuàng)建的方式有兩種,一種是棧上,一種是堆上創(chuàng)建。

  • {
  • Animal a; // stack
  • Animal *pa = new Animal(); // heap
  • }
  • 上面的代碼中,第一個對象創(chuàng)建在棧上,更明確的說法是它是一個局部變量,這意味著它的生命期起源于被創(chuàng)建的這行語句,終結(jié)與所在作用域的末尾,也就是這里的右花括號(})。
    而第二個對象呢?它是采用所謂的動態(tài)內(nèi)存分配生成的,需要程序員手工去釋放,當調(diào)用delete的時候才銷毀,但調(diào)用delete的時機不是固定的。
    也就是說,棧對象的生命期是明確的,而堆對象的生命期由于取決于調(diào)用delete的時機,因而是不明確的。

    看到這里,之前那段有可能內(nèi)存泄漏的代碼如何去改進呢?

    答案就是用棧對象明確的生命期去管理資源。

    用對象的生命期管理資源

    試想一下,如果我們把之前程序中,對內(nèi)存的分配寫在構(gòu)造函數(shù)中,把釋放資源寫在析構(gòu)函數(shù)中,而棧對象的生命期是明確的,當該管理資源的對象過期時,連同它管理的資源一起釋放,豈不是非常智能化?

    我們嘗試著寫出下列代碼:

  • class ScopePtr{
  • public:
  • ScopePtr(int *p):_p(p){
  • }
  • ~ScopePtr(){
  • delete[] _p;
  • }
  • private:
  • int *_p;
  • };
  • 我們把之前的代碼做如下的改進:

  • try{
  • ScopePtr scope(new int[100]);
  • // ... do something
  • }catch(exception &e){
  • // .....
  • }
  • 再來分析一下這段代碼:
    如果正常執(zhí)行,那么當執(zhí)行完try塊時,scope對象過期,執(zhí)行析構(gòu)函數(shù),同時釋放了那段數(shù)組。如果使用的過程中發(fā)生了異常,那么當程序進入catch塊時,同樣會銷毀try內(nèi)的局部變量。
    無論是哪種情況,內(nèi)存總是會被釋放。
    如果這里不是int,而是其他復(fù)雜的類型,使用這個封裝的ScopePtr是不是不太方便?顯然不會,我們?nèi)ブ剌d成員操作符就可以了,使它表現(xiàn)的像個指針,這就是一個最簡單的智能指針的產(chǎn)生。
    問題得到了完美的解決!

    資源獲取即初始化

    我們上面解決問題的辦法就是RAII技術(shù),RAII的含義是“資源獲取即初始化”,這個概念有兩個要點:

    • 獲得資源后立即放進管理對象
    • 管理對象運用析構(gòu)函數(shù)確保資源被釋放

    看另外一個例子:我們在訪問一些臨界區(qū)資源的時候通常需要加鎖,所以產(chǎn)生了下面的代碼:

  • {
  • mutex.lock();
  • //do sth..
  • mutex.unlock();
  • }
  • 這種方式是很容易出現(xiàn)問題的,例如程序中間遇見錯誤情況需要退出這個函數(shù),此時很容易忘記解鎖:

  • {
  • mutex.lock();
  • //do sth..
  • if(...){
  • return false // forgot to unlock
  • }
  • // ...
  • mutex.unlock();
  • }
  • 此時如果再次進行Lock操作,就造成了死鎖。
    解決這個問題的辦法仍然很簡單,我們?nèi)懸粋€類:

  • class MutexLockGuard{
  • public:
  • MutexLockGuard(MutexLock mutex):_mutex(mutex){
  • _mutex.lock();
  • }
  • ~MutexLockGuard(){
  • _mutex.unlock();
  • }
  • private:
  • MutexLock &_mutex;
  • };
  • 這樣剛才那段代碼就可以修改成:

  • {
  • MutexLockGuard guard(lock);
  • //do sth..
  • if(...){
  • return false
  • }
  • // ...
  • }
  • 這樣,一旦離開這段代碼,程序立刻自動解鎖。
    不過為了防止錯誤使用這個類,例如:

  • MutexLockGuard(lock);
  • 可以定義一個宏:

  • #define MutexLockGuard(m) "ERR MutexLockGuard"
  • 這樣我們在錯誤使用的時候,編譯期間就能發(fā)現(xiàn)錯誤。

    一種泛型解決方案

    劉未鵬在他的《C++11(及現(xiàn)代C++風格)和快速迭代式開發(fā)》中提出了一種泛型實現(xiàn),利用了C++11的function和Lambda匿名函數(shù),如下:

  • class ScopeGuard
  • {
  • public:
  • explicit ScopeGuard(std::function<void()> onExitScope)
  • : onExitScope_(onExitScope), dismissed_(false)
  • { }
  • ~ScopeGuard()
  • {
  • if(!dismissed_)
  • {
  • onExitScope_();
  • }
  • }
  • void Dismiss()
  • {
  • dismissed_ = true;
  • }
  • private:
  • std::function<void()> onExitScope_;
  • bool dismissed_;
  • private: // noncopyable
  • ScopeGuard(ScopeGuard const&);
  • ScopeGuard& operator=(ScopeGuard const&);
  • };
  • 使用方式也很簡單:

  • HANDLE h = CreateFile(...);
  • ScopeGuard onExit([&] { CloseHandle(h); });
  • 其實就是將該資源釋放的函數(shù)代碼段注冊到Scope類,其中原理不再贅述。

    與其他語言的對比

    RAII是C++獨有的編程手段。通過RAII技術(shù)我們能夠做到資源不需要使用時立即釋放,這是其他GC語言所不具備的。
    以Java為例,Java具有完善的GC(Garbage Collection,垃圾回收)機制,但是存在如下的缺點:

    • GC只能回收內(nèi)存,而對于打開的文件、數(shù)據(jù)庫連接等仍然需要手工關(guān)閉。
    • GC因為進程優(yōu)先級等原因,回收效率底下,詳情可以參考孟巖的《垃圾收集機制(Garbage Collection)批判》

    conclusion

    RAII技術(shù)是現(xiàn)代C++編程技術(shù)中及其重要的一部分,甚至有人稱其為“C++編程中最重要的編程技法”,可見其重要性。通過RAII,我們完全可以實現(xiàn)資源的自動化管理,寫出永不內(nèi)存泄漏的程序。

    參考資料

    • 《C++ Primer》
    • 《Effective C++》
    • 《Linux多線程服務(wù)器端編程》

    總結(jié)

    以上是生活随笔為你收集整理的用RAII技术管理资源及其泛型实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。