日本免费精品_最新日韩一区_亚洲视频一区在线_a在线视频观看_天天射夜夜骑_粉嫩av一区二区三区_欧美中日韩免费视频_综合图区欧美_国内精品美女在线观看_午夜精品久久久久久久男人的天堂

首頁 > 編程 > C++ > 正文

C++中的RAII機制詳解

2020-05-23 14:21:41
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了C++中的RAII機制詳解,RAII是Resource Acquisition Is Initialization的簡稱,是C++語言的一種管理資源、避免泄漏的慣用法,需要的朋友可以參考下
 
 

前言

在寫C++設計模式——單例模式的時候,在寫到實例銷毀時,設計的GC類是很巧妙的,而這一巧妙的設計就是根據當對象的生命周期結束時會自動調用其析構函數的,而這一巧妙的設計也是有專業的名詞的——RAII。那以下將圍繞RAII,全面的講解RAII的相關知識。

什么是RAII?

RAII是Resource Acquisition Is Initialization的簡稱,是C++語言的一種管理資源、避免泄漏的慣用法。利用的就是C++構造的對象最終會被銷毀的原則。RAII的做法是使用一個對象,在其構造時獲取對應的資源,在對象生命期內控制對資源的訪問,使之始終保持有效,最后在對象析構的時候,釋放構造時獲取的資源。

為什么要使用RAII?

上面說到RAII是用來管理資源、避免資源泄漏的方法。那么,用了這么久了,也寫了這么多程序了,口頭上經常會說資源,那么資源是如何定義的?在計算機系統中,資源是數量有限且對系統正常運行具有一定作用的元素。比如:網絡套接字、互斥鎖、文件句柄和內存等等,它們屬于系統資源。由于系統的資源是有限的,就好比自然界的石油,鐵礦一樣,不是取之不盡,用之不竭的,所以,我們在編程使用系統資源時,都必須遵循一個步驟:

1.申請資源;
2.使用資源;
3.釋放資源。

第一步和第二步缺一不可,因為資源必須要申請才能使用的,使用完成以后,必須要釋放,如果不釋放的話,就會造成資源泄漏。

一個最簡單的例子:

 

復制代碼代碼如下:

#include <iostream> 
 
using namespace std; 
 
int main() 
 

    int *testArray = new int [10]; 
    // Here, you can use the array 
    delete [] testArray; 
    testArray = NULL ; 
    return 0; 
}

 

我們使用new開辟的內存資源,如果我們不進行釋放的話,就會造成內存泄漏。所以,在編程的時候,new和delete操作總是匹配操作的。如果總是申請資源而不釋放資源,最終會導致資源全部被占用而沒有資源可用的場景。但是,在實際的編程中,我們總是會各種不小心的就把釋放操作忘了,就是編程的老手,在幾千行代碼,幾萬行中代碼中,也會犯這種低級的錯誤。

再來一個例子:

復制代碼代碼如下:

#include <iostream> 
using namespace std; 
 
bool OperationA(); 
bool OperationB(); 
 
int main() 

    int *testArray = new int [10]; 
 
    // Here, you can use the array 
    if (!OperationA()) 
    { 
        // If the operation A failed, we should delete the memory 
        delete [] testArray; 
        testArray = NULL ; 
        return 0; 
    } 
 
    if (!OperationB()) 
    { 
        // If the operation A failed, we should delete the memory 
        delete [] testArray; 
        testArray = NULL ; 
        return 0; 
    } 
 
    // All the operation succeed, delete the memory 
    delete [] testArray; 
    testArray = NULL ; 
    return 0; 

 
bool OperationA() 
 

    // Do some operation, if the operate succeed, then return true, else return false 
    return false ; 

 
bool OperationB() 
 

    // Do some operation, if the operate succeed, then return true, else return false 
    return true ; 
}

 

上述這個例子的模型,在實際中是經常使用的,我們不能期待每個操作都是成功返回的,所以,每一個操作,我們需要做出判斷,上述例子中,當操作失敗時,然后,釋放內存,返回程序。上述的代碼,極度臃腫,效率下降,更可怕的是,程序的可理解性和可維護性明顯降低了,當操作增多時,處理資源釋放的代碼就會越來越多,越來越亂。如果某一個操作發生了異常而導致釋放資源的語句沒有被調用,怎么辦?這個時候,RAII機制就可以派上用場了。

如何使用RAII?

當我們在一個函數內部使用局部變量,當退出了這個局部變量的作用域時,這個變量也就別銷毀了;當這個變量是類對象時,這個時候,就會自動調用這個類的析構函數,而這一切都是自動發生的,不要程序員顯示的去調用完成。這個也太好了,RAII就是這樣去完成的。由于系統的資源不具有自動釋放的功能,而C++中的類具有自動調用析構函數的功能。如果把資源用類進行封裝起來,對資源操作都封裝在類的內部,在析構函數中進行釋放資源。當定義的局部變量的生命結束時,它的析構函數就會自動的被調用,如此,就不用程序員顯示的去調用釋放資源的操作了。現在,我們就用RAII機制來完成上面的例子。代碼如下:

 

復制代碼代碼如下:

#include <iostream> 
using namespace std; 
 
class ArrayOperation 

public : 
    ArrayOperation() 
    { 
        m_Array = new int [10]; 
    } 
 
    void InitArray() 
    { 
        for (int i = 0; i < 10; ++i) 
        { 
            *(m_Array + i) = i; 
        } 
    } 
 
    void ShowArray() 
    { 
        for (int i = 0; i <10; ++i) 
        { 
            cout<<m_Array[i]<<endl; 
        } 
    } 
 
    ~ArrayOperation() 
    { 
        cout<< "~ArrayOperation is called" <<endl; 
        if (m_Array != NULL ) 
        { 
            delete[] m_Array;  // 非常感謝益可達非常犀利的review,詳細可以參加益可達在本文的評論 2014.04.13
            m_Array = NULL ; 
        } 
    } 
 
private : 
    int *m_Array; 
}; 
 
bool OperationA(); 
bool OperationB(); 
 
int main() 

    ArrayOperation arrayOp; 
    arrayOp.InitArray(); 
    arrayOp.ShowArray(); 
    return 0;
}

 

上面這個例子沒有多大的實際意義,只是為了說明RAII的機制問題。下面說一個具有實際意義的例子:

 

復制代碼代碼如下:

/*
** FileName     : RAII
** Author       : Jelly Young
** Date         : 2013/11/24
** Description  : More information, please go to http://www.conghuacea.com
*/
 
#include <iostream>
#include <windows.h>
#include <process.h>
 
using namespace std;
 
CRITICAL_SECTION cs;
int gGlobal = 0;
 
class MyLock
{
public:
    MyLock()
    {
        EnterCriticalSection(&cs);
    }
 
    ~MyLock()
    {
        LeaveCriticalSection(&cs);
    }
 
private:
    MyLock( const MyLock &);
    MyLock operator =(const MyLock &);
};
 
void DoComplex(MyLock &lock ) // 非常感謝益可達犀利的review 2014.04.13
{
}
 
unsigned int __stdcall ThreadFun(PVOID pv) 
{
    MyLock lock;
    int *para = (int *) pv;
 
    // I need the lock to do some complex thing
    DoComplex(lock);
 
    for (int i = 0; i < 10; ++i)
    {
        ++gGlobal;
        cout<< "Thread " <<*para<<endl;
        cout<<gGlobal<<endl;
    }
    return 0;
}
 
int main()
{
    InitializeCriticalSection(&cs);
 
    int thread1, thread2;
    thread1 = 1;
    thread2 = 2;
 
    HANDLE handle[2];
    handle[0] = ( HANDLE )_beginthreadex(NULL , 0, ThreadFun, ( void *)&thread1, 0, NULL );
    handle[1] = ( HANDLE )_beginthreadex(NULL , 0, ThreadFun, ( void *)&thread2, 0, NULL );
    WaitForMultipleObjects(2, handle, TRUE , INFINITE );
    return 0;
}

 

這個例子可以說是實際項目的一個模型,當多個進程訪問臨界變量時,為了不出現錯誤的情況,需要對臨界變量進行加鎖;上面的例子就是使用的Windows的臨界區域實現的加鎖。但是,在使用CRITICAL_SECTION時,EnterCriticalSection和LeaveCriticalSection必須成對使用,很多時候,經常會忘了調用LeaveCriticalSection,此時就會發生死鎖的現象。當我將對CRITICAL_SECTION的訪問封裝到MyLock類中時,之后,我只需要定義一個MyLock變量,而不必手動的去顯示調用LeaveCriticalSection函數。

上述的兩個例子都是RAII機制的應用,理解了上面的例子,就應該能理解了RAII機制的使用了。

使用RAII的陷阱

在使用RAII時,有些問題是需要特別注意的。容我慢慢道來。

先舉個例子:

 

復制代碼代碼如下:

#include <iostream>
#include <windows.h>
#include <process.h>
 
using namespace std;
 
CRITICAL_SECTION cs;
int gGlobal = 0;
 
class MyLock
{
public:
    MyLock()
    {
        EnterCriticalSection(&cs);
    }
 
    ~MyLock()
    {
        LeaveCriticalSection(&cs);
    }
 
private:
    //MyLock(const MyLock &);
    MyLock operator =(const MyLock &);
};
 
void DoComplex(MyLock lock)
{
}
 
unsigned int __stdcall ThreadFun(PVOID pv)  
{
    MyLock lock;
    int *para = (int *) pv;
 
    // I need the lock to do some complex thing
    DoComplex(lock);
 
    for (int i = 0; i < 10; ++i)
    {
        ++gGlobal;
        cout<< "Thread " <<*para<<endl;
        cout<<gGlobal<<endl;
    }
    return 0;
}
 
int main()
{
    InitializeCriticalSection(&cs);
 
    int thread1, thread2;
    thread1 = 1;
    thread2 = 2;
 
    HANDLE handle[2];
    handle[0] = ( HANDLE )_beginthreadex(NULL , 0, ThreadFun, ( void*)&thread1, 0, NULL );
    handle[1] = ( HANDLE )_beginthreadex(NULL , 0, ThreadFun, ( void*)&thread2, 0, NULL );
    WaitForMultipleObjects(2, handle, TRUE , INFINITE );
    return 0;
}

 

這個例子是在上個例子上的基礎上進行修改的。添加了一個DoComplex函數,在線程中調用該函數,該函數很普通,但是,該函數的參數就是我們封裝的類。你運行該代碼,就會發現,加入了該函數,對gGlobal全局變量的訪問整個就亂了。你有么有想過,這是為什么呢?網上很多講RAII的文章,都只是說了這個問題,但是沒有說為什么,在這里,我好好的分析一下這里。

由于DoComplex函數的參數使用的傳值,此時就會發生值的復制,會調用類的復制構造函數,生成一個臨時的對象,由于MyLock沒有實現復制構造函數,所以就是使用的默認復制構造函數,然后在DoComplex中使用這個臨時變量。當調用完成以后,這個臨時變量的析構函數就會被調用,由于在析構函數中調用了LeaveCriticalSection,導致了提前離開了CRITICAL_SECTION,從而造成對gGlobal變量訪問沖突問題,如果在MyLock類中添加以下代碼,程序就又能正確運行:

復制代碼代碼如下:

MyLock( const MyLock & temp ) 

    EnterCriticalSection(&cs); 
}

 

這是因為CRITICAL_SECTION 允許多次EnterCriticalSection,但是,LeaveCriticalSection必須和EnterCriticalSection匹配才能不出現死鎖的現象。

為了避免掉進了這個陷阱,同時考慮到封裝的是資源,由于資源很多時候是不具備拷貝語義的,所以,在實際實現過程中,MyLock類應該如下:

 

復制代碼代碼如下:

class MyLock
{
public:
    MyLock()
    {
        EnterCriticalSection(&cs);
    }
 
    ~MyLock()
    {
        LeaveCriticalSection(&cs);
    }
 
private:
    MyLock(const MyLock &);
    MyLock operator =(const MyLock &);
};

 

這樣就防止了背后的資源復制過程,讓資源的一切操作都在自己的控制當中。如果要知道復制構造函數和賦值操作符的調用,可以好好的閱讀一下《深度探索C++對象模型這本書》。

總結

說了這么多了,RAII的本質內容是用對象代表資源,把管理資源的任務轉化為管理對象的任務,將資源的獲取和釋放與對象的構造和析構對應起來,從而確保在對象的生存期內資源始終有效,對象銷毀時資源一定會被釋放。說白了,就是擁有了對象,就擁有了資源,對象在,資源則在。所以,RAII機制是進行資源管理的有力武器,C++程序員依靠RAII寫出的代碼不僅簡潔優雅,而且做到了異常安全。在以后的編程實際中,可以使用RAII機制,讓自己的代碼更漂亮。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
在线观看免费国产成人软件| 久久久精品免费免费| 一区二区中文视频| 欧美日韩国产一级片| 日韩欧美成人一区二区三区| 最新中文字幕在线播放| 蜜桃视频一日韩欧美专区| 欧美日韩国产免费观看视频| 欧美不卡一二三| 日韩av一区在线| 日韩欧美在线字幕| 日韩欧美在线中文字幕| 在线一区免费| 久久99久久久久| 久久综合九色欧美综合狠狠| 日韩视频在线一区二区| 日韩中文字幕在线观看视频| 国产在线拍揄自揄拍| 欧美日韩中文字幕综合视频| 亚洲校园欧美国产另类 | 亚洲黄页一区| 99久久精品国产成人一区二区| 欧美成人vr18sexvr| 国产91久久久久| 在线亚洲人成| 区日韩二区欧美三区| 国产在线拍偷自揄拍精品| 国产激情在线| 天堂中文在线视频| 国产福利精品导航| 国产在线日韩精品| 国产欧美日韩在线看| 日韩精品在线播放| 精品国内自产拍在线视频| 日韩一级二级三级| 国产欧美日韩视频在线| 国产性一级片| 午夜精品一区二区三区免费视频| 自拍日韩亚洲一区在线| 亚洲 欧美 精品| 亚洲国产福利视频| 欧美日韩国产综合网| 粉嫩粉嫩芽的虎白女18在线视频| 国产一级在线播放| 91精品综合久久久久久| 精品九九久久| www.eeuss影院| 日韩中文字幕精品视频| 在线一区av| wwwav在线播放| 国产三级精品在线观看| 亚洲视频在线观看日本a| 欧美日韩国产首页在线观看| 国产一二三四| 亚洲乱码中文字幕综合| 亚洲第一视频在线观看| 欧美日韩乱国产| 国产绿帽一区二区三区| 欧美日韩中文字幕一区| 欧美日韩亚洲系列| 粉嫩喷白浆久久| 亚洲免费婷婷| 欧美va亚洲va日韩∨a综合色| 久久视频www| 久久精品最新免费国产成人| 中文字幕精品视频| 精品在线观看一区| 91xxx在线观看| 国产日韩精品在线| 欧美日韩亚洲不卡| 国产欧美日韩精品高清二区综合区 | 欧美高清一级片在线| 国产小视频在线观看| 视频一区二区中文字幕| 国产日韩精品在线观看| 欧美日韩国产一区| 最近中文字幕第一页| 欧美三级免费观看| 国产午夜精品视频免费不卡69堂| 婷婷中文字幕在线观看| 亚洲人成欧美中文字幕| 欧美日韩一级片在线观看| 91精品网站| 最近中文av字幕在线中文| 国产日韩在线亚洲字幕中文| 亚洲成年人影院在线| 国产wwww| 国产成免费视频| 一区二区三区中文字幕在线观看| 一区二区三区在线免费| 国产v日产∨综合v精品视频| 国产日韩在线视频| 亚洲中文字幕在线一区| 视频一区二区中文字幕| 视频一区中文字幕国产| 日韩不卡在线观看| 91精品国产91久久久久久久久| 国产区在线看| 精品日韩在线观看| 91精品国产乱码久久蜜臀| 日韩视频 中文字幕| 亚洲免费福利视频| 亚洲高清在线观看一区| 日韩中文字幕国产| 国产一级粉嫩xxxx| 国产一卡2卡3卡4卡网站免费| 欧美日韩在线观看一区| 国产午夜精品全部视频播放| 91精品免费看| 91精品国产全国免费观看| 精品区一区二区| 欧美.日韩.国产.一区.二区| 中文字幕 欧美日韩| 国产福利在线播放| 国产在线不卡一区| 欧美色欧美亚洲高清在线视频| 亚洲成人7777| 中文字幕亚洲区| 亚洲免费精品| 欧美亚洲国产日韩2020| 欧美日韩亚洲国内综合网俺| 国产欧美日韩在线| 国产日韩精品在线看| 久久精品欧美日韩精品| 亚洲经典中文字幕| 日韩亚洲欧美中文三级| 黄色一区二区视频| 在线看av的网址| 国产成人精品av久久| 中文av字幕一区| 91日韩欧美| 亚洲综合在线视频| 国产69精品久久久久孕妇国产69久久| 色99中文字幕| 日韩中文字幕国产| 日韩精品国产欧美| 99精品电影| lutube成人福利在线观看| 在线不卡日本| 日韩在线不卡| 日韩欧美在线视频日韩欧美在线视频| 日韩美女视频一区二区在线观看| 欧美国产综合视频| 国产最新在线| 日韩视频精品在线观看| 亚洲综合在线视频| 91精品国产免费| 91精品啪在线观看国产60岁| 日韩av一区二| 91久久久久久久久| 日韩欧美看国产| 欧美在线视频第一页| 中文字幕在线视频第一页| 国产一卡二卡3卡4卡四卡在线| 91精品国产91久久久久| 欧美一级一级性生活免费录像| 日韩免费视频| 国产区高清在线| 日韩中文字幕在线视频播放| 久久99久久久久久久噜噜| 精品福利在线观看| 国产小视频在线观看免费| 最新中文在线视频| 欧美日韩亚洲不卡| 日韩在线视频二区| 中文字幕久久精品| 日韩欧美国产一二三区| 91九色精品视频| www在线播放| 日韩手机在线观看视频| 欧美99久久| a天堂中文在线官网在线| 在线亚洲免费| 欧美在线视频第一页| av免费在线观看网址| 欧美日韩性视频| 欧美熟妇乱码在线一区| 久久精品国产91精品亚洲| 91久久中文| 久久在线91| 欧美日韩精品中文字幕| 久久精品电影| 1024国产在线| 91麻豆精品国产91久久久使用方法| 国产成人一区二区精品非洲| 成人h视频在线观看| 国产一级久久久| 日韩在线观看一区| 中文字幕乱码在线| 亚洲美女视频一区| 日韩一级网站| 日韩欧美亚洲视频| 成人禁用看黄a在线| 日韩视频在线观看视频| 日韩欧美中文字幕一区| 国产一卡2卡3卡免费网站| 日本精品专区| 国产免费一级| 在线欧美日韩精品| 亚洲一区中文| 欧美日韩国产在线看| 天天综合色天天| 国产小视频在线观看免费| 国产黄色在线观看| 亚洲制服丝袜一区| 精品免费视频| av免费不卡国产观看| 国产欧美久久久精品免费| 欧美日韩高清在线一区| 91精品国产91久久| 中文字幕日韩在线观看| 久久视频www| 欧美三级在线播放| 一区二区国产在线| 日韩精品视频网站| 日韩av一区在线| 7799精品视频天天看| 中文欧美字幕免费| 国产成免费视频| 在线不卡一区二区| 国产69精品久久久久孕妇国产69久久 | 蜜臀91精品国产高清在线观看| 免费精品国产自产拍观看| 久久99精品国产| 亚洲国产福利视频| 欧美一级免费看| 日韩精品欧美| 中文官网资源新版中文第二页在线观看 | 日韩中文在线字幕| 粉嫩喷白浆久久| 一区在线播放视频| 日韩在线三区| 欧美日韩乱国产| 久久久久久91| 91精品国产色综合久久不卡蜜臀| 人成在线免费视频| www日韩欧美| 欧美日韩综合在线免费观看| 亚洲乱码一区av黑人高潮| www中文字幕在线观看| 国产一卡2卡3卡四卡网站| 国产日韩中文字幕在线| 色综合久久六月婷婷中文字幕| 欧美在线视频第一页| 在线精品观看| 国产高清大尺度一区二区不卡| 国产在线中文字幕| 男人的天堂网av| 中文字幕第一页在线播放| 亚洲娇小xxxx欧美娇小| 中文字幕在线观看亚洲| 九一久久久久久| 蜜桃久久久久| 日韩欧美中文在线| 一区二区不卡久久精品| 极品久久久久久| 国产高清视频一区二区| wwwww亚洲| 国产欧美日韩在线视频| 国产天堂素人系列在线视频| 日韩欧美综合| 久草亚洲一区| 91精品国产91综合久久蜜臀| 日韩中文字幕二区| 国产视频不卡| 欧美日韩综合在线观看| 欧美日韩国产观看视频| 国产成人精品网址| 日韩精品在线网站| 在线视频色在线| 91精品国产入口| 中文字幕人成乱码在线观看| 久久欧美中文字幕| 国产拍揄自揄精品视频麻豆| 亚洲一区二区三区精品中文字幕| 国产三级视频网站| 日韩av一区在线| 欧美日韩国产高清视频| 在线视频色在线| 午夜伊人狠狠久久| 顶级网黄在线播放| 免费中文字幕日韩欧美| 日韩国产欧美亚洲| 欧美婷婷久久| 亚洲免费精品视频| 久久福利视频一区二区| www.91香蕉视频| 亚洲一区中文字幕在线观看| 激情五月综合| 白嫩少妇丰满一区二区| 日韩wumaV| 91精品国产综合久久久久| 亚洲黄色一区二区| 国产裸体歌舞团一区二区| 欧美日韩中文字幕视频| 国产69精品久久久久孕妇国产69久久 | 日本免费看黄| 日韩精品福利视频| 日本一级一片免费视频| 高清1区2区| 亚洲综合在线小说| 欧美日韩国产免费观看视频| 日韩精品乱码av一区二区| 精品久久在线| 久久视频在线免费观看| 亚洲福利精品视频| 日韩精品福利视频| 欧美日韩亚洲一| 国产欧美日韩在线视频| 中文字幕成人乱码在线电影| 欧美日韩国产系列| 久草中文在线观看| 国产视频一区三区| 亚洲一区在线视频观看| 国产在线观看色| 欧美日韩精品国产| 国产一级免费看| 日韩欧中文字幕| 蜜桃视频一日韩欧美专区| 中文不卡在线| 91最新在线| 亚洲国产无线乱码在线观看| 一区二区三区在线免费| 久久欧美中文字幕| 婷婷中文字幕一区三区| 国产一级久久久| 日韩中文字幕在线视频观看| 在线看欧美日韩| 日韩视频不卡中文| 国产欧美日韩在线视频| 亚洲专区一二三| 日韩一级中文字幕| 国产成人精品av久久| 日韩不卡在线观看| 欧美日韩久久久| 91九色在线播放| 欧美 日韩 中文字幕| 欧美高清一区| 中文字幕五月天| 日韩国产专区| 精品视频999| 韩国av一区二区| 国产极品嫩模在线视频一区| 不卡中文一二三区| 日韩中文字幕在线视频播放 | 一级日韩一级欧美| 中文国产字幕在线观看| 亚洲娇小xxxx欧美娇小| 一区二区欧美国产| 日韩精品大片| 欧美日韩高清| 日韩高清在线不卡| 欧美亚洲国产日韩2020| 日韩av一区二| 久久中文免费视频| 亚洲一区日韩精品中文字幕| 亚洲国产福利| 欧美日韩亚洲91| av一区二区高清| 国产免费电影网站入口| 国产欧美日韩最新| wwwav在线播放| 日韩 欧美 综合| 国产一卡二卡3卡4卡四卡在线| 欧美日韩视频在线| 亚洲一区日韩精品中文字幕| 国产一区深夜福利| 国产黄色在线| 国产一级免费| 欧美 日韩 国产 在线| 国产一区久久久| 91久久久久| 日本a级黄色| 欧美xxxx中国| 日韩你懂的电影在线观看| 欧美日韩中文字幕一区| 日韩欧美中文在线视频| 在线一区av| 91久久在线| 欧美乱大交xxxxx另类| 日韩欧美在线视频日韩欧美在线视频| 国产在线导航| 欧美精品一区二区三区在线播放| 日韩精品视频免费看| 五月天久久比比资源色| 国产亚洲污的网站| 一区在线播放视频| 精品国产欧美日韩不卡在线观看| 欧美日韩激情在线一区二区三区 | 欧美日韩三级视频| 中文字幕在线播放一区| 国产一区在线观看视频| 日韩精品a在线观看91| 日韩三级视频在线看| 二区三区不卡不卡视频| 日韩你懂的电影在线观看| 国产在线高潮| 日韩av不卡在线观看| 日韩在线三区| 国产一级网站视频在线|