av激情亚洲男人的天堂国语,日韩欧美精品一中文字幕,无码av一区二区三区无码,国产又色又爽又刺激的a片,国产又色又爽又刺激的a片

C++程序的設計機制3 RAII機制

RAII(Resource Acquisition Is Initialization )機制是Bjarne Stroustrup首先提出的。要解決的是這樣一個問題:

專注于為中小企業(yè)提供成都網站設計、成都網站建設、外貿網站建設服務,電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)永登免費做網站提供優(yōu)質的服務。我們立足成都,凝聚了一批互聯(lián)網行業(yè)人才,有力地推動了上千家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網站建設實現(xiàn)規(guī)模擴充和轉變。

在C++中,如果在這個程序段結束時需要完成一些資源釋放工作,那么正常情況下自然是沒有什么問題,但是當一個異常拋出時,釋放資源的語句就不會被執(zhí)行。于是Bjarne Stroustrup就想到確保能運行資源釋放代碼的地方就是在這個程序段(棧幀)中放置的對象的析構函數(shù)了,因為stack winding會保證它們的析構函數(shù)都會被執(zhí)行。將初始化和資源釋放都移動到一個包裝類中的好處:

  • 保證了資源的正常釋放
  • 省去了在異常處理中冗長而重復甚至有些還不一定執(zhí)行到的清理邏輯,進而確保了代碼的異常安全。
  • 簡化代碼體積。

1、應用場景

1)文件操作

我們可以是用這個機制將文件操作包裝起來完成一個異常安全的文件類。實現(xiàn)上,注意將復制構造函數(shù)和賦值符私有化,這個是通過一個私有繼承類完成的,因為這兩個操作在此并沒有意義,當然這并不是RAII所要求的。

 
 
 
  1. /*  
  2. * =====================================================================================  
  3. *  
  4. * Filename: file.cpp  
  5. *  
  6. * Description: RAII for files  
  7. *  
  8. * Version: 1.0  
  9. * Created: 05/09/2011 06:57:43 PM  
  10. * Revision: none  
  11. * Compiler: g++  
  12. *  
  13. * Author: gnuhpc (http://blog.csdn.net/gnuhpc), [email protected]  
  14. *  
  15. * =====================================================================================  
  16. */  
  17. #include   
  18. #include   
  19. #include   
  20.  
  21. using namespace std;  
  22. class NonCopyable  
  23. {  
  24. public:  
  25. NonCopyable(){};  
  26. private:  
  27. NonCopyable (NonCopyable const &); // private copy constructor  
  28. NonCopyable & operator = (NonCopyable const &); // private assignment operator  
  29. };  
  30.  
  31. class SafeFile:NonCopyable{  
  32. public:  
  33. SafeFile(const char* filename):fileHandler(fopen(filename,"w+"))  
  34. {  
  35. if( fileHandler == NULL )  
  36. {  
  37. throw runtime_error("Open Error!");  
  38. }  
  39. }  
  40. ~SafeFile()  
  41. {  
  42. fclose(fileHandler);  
  43. }  
  44.  
  45. void write(const char* str)  
  46. {  
  47. if( fputs(str,fileHandler)==EOF )  
  48. {  
  49. throw runtime_error("Write Error!");  
  50. }  
  51. }  
  52.  
  53. void write(const char* buffer, size_t num)  
  54. {  
  55. if( num!=0 && fwrite(buffer,num,1,fileHandler)==0 )  
  56. {  
  57. throw runtime_error("Write Error!");  
  58. }  
  59. }  
  60. private:  
  61. FILE *fileHandler;  
  62. SafeFile(const SafeFile&);  
  63. SafeFile &operator =(const SafeFile&);  
  64. };  
  65.  
  66. int main(int argc, char *argv[])  
  67. {  
  68. SafeFile testVar("foo.test");  
  69. testVar.write("Hello RAII");  

C++的結構決定了其原生支持RAII,而在Java 中,對象何時銷毀是未知的,所以在Java 中可以使用try-finally做相關處理。

#p#

2)智能指針模擬

一個更復雜一點的例子是模擬智能指針,抽象出來的RAII類中實現(xiàn)了一個操作符*,直接返回存入的指針:

現(xiàn)在我們有一個類:

 
 
 
  1. class Example {  
  2. SomeResource* p_;  
  3. SomeResource* p2_;  
  4. public:  
  5. Example() :  
  6. p_(new SomeResource()),  
  7. p2_(new SomeResource()) {  
  8. std::cout << "Creating Example, allocating SomeResource!\n";  
  9. }  
  10. Example(const Example& other) :  
  11. p_(new SomeResource(*other.p_)),  
  12. p2_(new SomeResource(*other.p2_)) {}  
  13. Example& operator=(const Example& other) {  
  14. // Self assignment?  
  15. if (this==&other)  
  16. return *this;  
  17. *p_=*other.p_;  
  18. *p2_=*other.p2_;  
  19. return *this;  
  20. }  
  21. ~Example() {  
  22. std::cout << "Deleting Example, freeing SomeResource!\n";  
  23. delete p_;  
  24. delete p2_;  
  25. }  
  26. }; 

假設在創(chuàng)建SomeResource的時候可能會有異常,那么當p_指向的資源被創(chuàng)建但p2_指向的資源創(chuàng)建失敗時,Example的實例就整個創(chuàng)建失敗,那么p_指向的資源就存在內存泄露問題。

用下邊的這個方法可以為權宜之計:

 
 
 
  1. Example() : p_(0),p2_(0)  
  2. {  
  3. try {  
  4. p_=new SomeResource();  
  5. p2_=new SomeResource("H",true);  
  6. std::cout << "Creating Example, allocating SomeResource!\n";  
  7. }  
  8. catch(...) {  
  9. delete p2_;  
  10. delete p_;  
  11. throw;  
  12. }  

但是我們可以利用一個對象在離開一個域中會調用析構函數(shù)的特性,在構造函數(shù)中完成初始化,在析構函數(shù)中完成清理工作,將需要操作和保護的指針作為成員變量放入RAII中。

 
 
 
  1. template   
  2. class RAII {  
  3. T* p_;  
  4. public:  
  5. explicit RAII(T* p) : p_(p) {}  
  6. ~RAII() {  
  7. delete p_;  
  8. }  
  9. void reset(T* p) {  
  10. delete p_;  
  11. p_=p;  
  12. }  
  13. T* get() const {  
  14. return p_;  
  15. }  
  16. T& operator*() const {  
  17. return *p_;  
  18. }  
  19. void swap(RAII& other) {  
  20. std::swap(p_,other.p_);  
  21. }  
  22. private:  
  23. RAII(const RAII& other);  
  24. RAII& operator=(const RAII& other);  
  25. }; 

我們在具體使用把保護的指針Someresource放在RAII中:

 
 
 
  1. class Example {  
  2. RAII p_;  
  3. RAII p2_;  
  4. public:  
  5. Example() :  
  6. p_(new SomeResource()),  
  7. p2_(new SomeResource()) {}  
  8. Example(const Example& other)  
  9. : p_(new SomeResource(*other.p_)),  
  10. p2_(new SomeResource(*other.p2_)) {}  
  11. Example& operator=(const Example& other) {  
  12. // Self assignment?  
  13. if (this==&other)  
  14. return *this;  
  15. *p_=*other.p_;  
  16. *p2_=*other.p2_;  
  17. return *this;  
  18. }  
  19. ~Example() {  
  20. std::cout << "Deleting Example, freeing SomeResource!\n";  
  21. }  
  22. }; 

現(xiàn)在即使p_成功而p2_失敗,那么在Stack winding時也會調用RAII的析構函數(shù)保證了p_指向的Someresource被析構。這種方法較之例1中需要實現(xiàn)被組合的指針類型相應的接口不同,這里不需要對接口進行封裝。當然,在例1中,你也可以提供一個getPointer的函數(shù)直接將句柄提供出來。

其實在Example中,已經不需要析構函數(shù)了,因為RAII類會幫它照顧好這一切的。這有點像auto_ptr,本文并不打算深入討論智能指針這個話題。

#p#

3)鎖操作

 
 
 
  1. /*  
  2. * =====================================================================================  
  3. *  
  4. * Filename: threadlock.cpp  
  5. *  
  6. * Description: Lock for RAII  
  7. *  
  8. * Version: 1.0  
  9. * Created: 05/09/2011 10:16:13 PM  
  10. * Revision: none  
  11. * Compiler: g++  
  12. *  
  13. * Author: gnuhpc (http://blog.csdn.net/gnuhpc), [email protected]  
  14. *  
  15. * =====================================================================================  
  16. */ 
  17. #include   
  18. #include   
  19. #include   
  20. int counter = 0;  
  21. void* routine(void *ptr);  
  22. pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  
  23. class NonCopyable  
  24. {  
  25. public:  
  26. NonCopyable(){};  
  27. private:  
  28. NonCopyable (NonCopyable const &); // private copy constructor  
  29. NonCopyable & operator = (NonCopyable const &); // private assignment operator  
  30. };  
  31. class ScopeMutex:NonCopyable  
  32. {  
  33. public:  
  34. ScopeMutex(pthread_mutex_t* mutex):mutex_(mutex){  
  35. pthread_mutex_lock( mutex_ );  
  36. }  
  37. ~ScopeMutex(){  
  38. pthread_mutex_unlock( mutex_ );  
  39. }  
  40. private:  
  41. pthread_mutex_t *mutex_;  
  42. };  
  43. int main(int argc, char *argv[])  
  44. {  
  45. int rc1, rc2;  
  46. pthread_t thread1, thread2;  
  47. if( (rc1=pthread_create( &thread1, NULL, routine, NULL)) )  
  48. {  
  49. printf("Thread creation failed: %d\n", rc1);  
  50. }  
  51. if( (rc2=pthread_create( &thread2, NULL, routine, NULL)) )  
  52. {  
  53. printf("Thread creation failed: %d\n", rc1);  
  54. }  
  55. pthread_join( thread1, NULL);  
  56. pthread_join( thread2, NULL);  
  57. }  
  58. void* routine(void *ptr)  
  59. {  
  60. ScopeMutex scopeMutex(&mutex);  
  61. counter++;  
  62. printf("%d\n",counter);  

2.總結

RAII機制保證了異常安全,并且也為程序員在編寫動態(tài)分配內存的程序時提供了安全保證。缺點是有些操作可能會拋出異常,如果放在析構函數(shù)中進行則不能將錯誤傳遞出去,那么此時析構函數(shù)就必須自己處理異常。這在某些時候是很繁瑣的。

【編輯推薦】

  1. C/C++返回內部靜態(tài)成員的陷阱
  2. 再駁Linus:思科工程師對C++不得不說的事
  3. C/C++是程序員必須掌握的語言嗎?
  4. 淺析C++中的動態(tài)多維數(shù)組
  5. Visual C++中實現(xiàn)對圖像數(shù)據(jù)的讀取顯示

當前名稱:C++程序的設計機制3 RAII機制
本文鏈接:http://uogjgqi.cn/article/dpshohp.html
掃二維碼與項目經理溝通

我們在微信上24小時期待你的聲音

解答本文疑問/技術咨詢/運營咨詢/技術建議/互聯(lián)網交流