C++程序的设计机制3 RAII机制(2)

 C++程序的设计 机制3 RAII机制(2)

为了管理内存等资源,C++程序员通常采用RAII机制(资源获取即初始化),在使用资源的类的构造函数中申请资源,然后使用,最后在析构函数中释放资源。今天本文为你介绍RAII机制,一起来看。

AD

2)智能指针模拟

一个更复杂一点的例子是模拟智能指针,抽象出来的RAII类中实现了一个操作符*,直接返回存入的指针:

现在我们有一个类:

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. }; 

假设在创建SomeResource的时候可能会有异常,那么当p_指向的资源被创建但p2_指向的资源创建失败时,Example的实例就整个创建失败,那么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. }  

13.

但是我们可以利用一个对象在离开一个域中会调用析构函数的特性,在构造函数中完成初始化,在析构函数中完成清理工作,将需要操作和保护的指针作为成员变量放入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. }; 

现在即使p_成功而p2_失败,那么在Stack winding时也会调用RAII的析构函数保证了p_指向的Someresource被析构。这种方法较之例1中需要实现被组合的指针类型相应的接口不 同,这里不需要对接口进行封装。当然,在例1中,你也可以提供一个getPointer的函数直接将句柄提供出来。

其实在Example中,已经不需要析构函数了,因为RAII类会帮它照顾好这一切的。这有点像auto_ptr,本文并不打算深入讨论智能指针这个话题。参考资料http://wenku.it168.com/d_000773512.shtml

你可能感兴趣的:(C++,设计,程序,机制)