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

posted @ 2011-07-18 18:45  yub0yue  阅读(250)  评论(0编辑  收藏  举报