Thinking in C++ 學習筆記(2)

Thinking in C++ 學習筆記(2)
關於C++ 中的RAII(Resource Acquisition In Initialisation) Wrapper

問題:class的構造函數中如果出現異常而被捕獲中止,則對象構造不完整, 相應的析構函數也不會被調用。 如果在構造的異常出現之前已經有指向其它對象的堆指針被實例化, 由於該對象的析構函數
不被調用,而使得對象的堆指針指出的堆內存不被釋放。

如:
  1 //: C01:Rawp.cpp
  2 //Naked pointer           
  3 
  4 #include <iostream>       
  5 #include <cstddef>        
  6    
  7 using namespace std;      
  8    
  9 class Cat {
 10 public:                   
 11     Cat() {cout << "Cat ()" << endl;}
 12     virtual ~Cat() {cout << "~Cat()" << endl;}
 13 }; 
 14    
 15 class Dog {
 16 public:
 17     void *operator new(size_t sz) {
 18         cout << "allocating a Dog" << endl; 
 19         throw 47;
 20     }
 21    
 22     void operator delete(void* p) {
 23         cout << "deallocating a Dog" << endl;
 24         ::operator delete(p);
 25     }
 26 };
 27 
 28 class UseResource {
 29     Cat* bp;
 30     Dog* op;
 31 public:
 32     UseResource(int count = 1) {
 33         cout << "UseResources()" << endl;
 34         bp = new Cat[count];
 35         op = new Dog;
 36     }
 37     virtual ~UseResource() {
 38         cout << "~UseResource()" << endl;
 39         delete[] bp;
 40         delete op;
 41     }
 42 };
 43 
 44 int main()
 45 {
 46     try {
 47         UseResource ur(3);
 48     } catch (int) {
 49         cout << "inside handler" << endl;
 50     }
 51 }
解決方法:
1 在構造函數中使用try{} catch() {}捕獲異常並且進行處理。
2 將nake pointer的分配內存過程由另外一個對象的構造函數來實現,
而釋放內存過程由另外一個對象的析構函數來完成。

對於2的實例如下:
  1 //: C01:Wrapped.cpp
  2 // Saft atomic pointers
  3 
  4 #include <iostream> 
  5 #include <cstddef> 
  6 using namespace std;
  7 
  8 template<class T, int sz = 1>
  9 class PWrap {
 10     T* ptr;
 11 public: 
 12     
 13     class RangeError{};
 14     PWrap() {
 15         ptr = new T[sz];    
 16         cout << "PWrap Constructor" << endl;
 17     }
 18     virtual ~PWrap () {
 19         delete[] ptr;
 20         cout << "PWrap Destructor" << endl; 
 21     }
 22 
 23     T& operator [] (int i) throw (RangeError) {
 24         if (i >= 0 && i < sz) {
 25             return ptr[i];
 26         }
 27         throw RangeError();
 28     }
 29 };
 30 
 31 
 32 class Cat {
 33 public:
 34     Cat() {cout << "Cat()" << endl;}
 35     virtual ~Cat() {cout << "~Cat" << endl;}
 36     void g() {};
 37 };
 38 
 39 class Dog {
 40 public :
 41     void *operator new[] (size_t ) {
 42         cout << "allocating a Dog" << endl;
 43         throw 47;
 44     }
 45 
 46     void operator delete[](void* p) {
 47         cout << "Deallocating a Dog" << endl;
 48         ::operator delete[] (p);
 49     }
 50 };
 51 
 52 class UseResource {
 53     PWrap<Cat, 3> cats;
 54     PWrap<Dog> dog;
 55 public:
 56     UseResource() { cout << "UseResource()" << endl;}
 57     virtual ~UseResource() { cout << "~UseResource()" << endl;}
 58     void f() { cats[1].g();}
 59 };
 60 
 61 int main() {
 62     try {
 63         UseResource ur;
 64     } catch (int) {
 65         cout << "inside handler" << endl;
 66     }
 67 }
在c++中,<memory>中的auto_ptr 就是這樣一個RAII Wrapper模板。
其使用方式如下:

  1 //: C01:Auto_ptr.cpp
  2 // auto_ptr template for wrapping raw pointer
  3 
  4 #include <iostream>       
  5 #include <cstddef> //for size_t type
  6    
  7 using namespace std;      
  8    
  9 class TraceHeap {         
 10     int i;                
 11 public:
 12     static void * operator new (size_t size) { 
 13         void * p = ::operator new(size);    
 14         cout << "Allocating TraceHeap object on the heap"
 15              << " at address "
 16              << p << endl;
 17         return p;         
 18     }
 19    
 20     static void operator delete(void* p) {
 21         cout << "Deallocating TraceHeap object at address " 
 22              << p << endl;
 23         ::operator delete(p); 
 24     }                     
 25 
 26     TraceHeap(int i) : i(i) {
 27     
 28     }
 29    
 30     int getVal() const {return i;} 
 31 };
 32    
 33 int main() {
 34     auto_ptr<TraceHeap> pMyObject(new TraceHeap(3));
 35     cout << pMyObject->getVal() << endl;
 36 }  
運行結果:
Allocating TraceHeap object on the heap at address 0x502010
3
Deallocating TraceHeap object at address 0x502010
發佈了31 篇原創文章 · 獲贊 3 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章