Chinaunix首页 | 论坛 | 博客
  • 博客访问: 350875
  • 博文数量: 63
  • 博客积分: 1412
  • 博客等级: 中尉
  • 技术积分: 648
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-10 23:07
文章分类

全部博文(63)

文章存档

2012年(42)

2011年(21)

我的朋友

分类: C/C++

2012-08-13 15:13:04

Resource


  Acquisition Is Initialization[edit]Intent
  • To guarantee release of resource(s) at the end of a scope
  • To provide basic exception safety guarantee
[edit]Also Known As
  • Execute-Around Object
  • Resource Release Is Finalization
  • Scope-Bound Resource Management
[edit]Motivation

Resources acquired in a function scope should be released before leaving the scope unless the ownership is being transferred to another scope or object. Quite often it means a pair of function calls - one to acquire a resource and another one to release it. For example, new/delete, malloc/free, acquire/release, file-open/file-close, nested_count++/nested_count--, etc. It is quite easy to forget to write the "release" part of the resource management "contract". Sometimes the resource release function is never invoked: this can happen when the control flow leaves the scope because of return or an exception. It is too dangerous to trust the programmer that he or she will invoke resource release operation in all possible cases in the present and in the future. Some examples are given below.


点击(此处)折叠或打开

  1. void foo ()
  2. {
  3.   char * ch = new char [100];
  4.   if (...)
  5.      if (...)
  6.         return;
  7.      else if (...)
  8.             if (...)
  9.   else
  10.      throw "ERROR";
  11.  
  12.   delete [] ch; // This may not be invoked... memory
  13. }
  14. void bar ()
  15. {
  16.   lock.acquire();
  17.   if (...)
  18.      if (...)
  19.         return;
  20.   else
  21.      throw "ERROR";
  22.  
  23.   lock.release(); // This may not be invoked...
  24. }

This is in general control flow abstraction problem. Resource Acquisition is Initialization (RAII) is an extremely popular idiom in C++ that relieves the burden of calling "resource release" operation in a clever way.

[edit]Solution and Sample Code

The idea is to wrap the resource release operation in a destructor of an object in the scope. Language guarantees that the destructor will always be invoked (of a successfully constructed object) when control flow leaves the scope because of a return statement or an exception.


点击(此处)折叠或打开

  1. // Private copy constructor and copy assignment ensure classes derived
  2. // from class NonCopyable cannot be copied.
  3. class NonCopyable
  4. {
  5.    NonCopyable (NonCopyable const &); // private copy constructor
  6.    NonCopyable & operator = (NonCopyable const &); // private assignment operator
  7. };
  8. template <class T>
  9. class AutoDelete : NonCopyable
  10. {
  11.   public:
  12.     AutoDelete (T * p = 0) : ptr_(p) {}
  13.     ~AutoDelete () throw() { delete ptr_; }
  14.   private:
  15.     T *ptr_;
  16. };
  17.  
  18. class ScopedLock : NonCopyable// Scoped Lock idiom
  19. {
  20.   public:
  21.     ScopedLock (Lock & l) : lock_(l) { lock_.acquire(); }
  22.     ~ScopedLock () throw () { lock_.release(); }
  23.   private:
  24.     Lock& lock_;
  25. };
  26.  
  27. void foo ()
  28. {
  29.   X * p = new X;
  30.   AutoDelete<X> safe_del(p); // Memory will not leak
  31.   if (...)
  32.     if (...)
  33.       return;
  34.  
  35.   // No need to call delete here.
  36.   // Destructor of safe_del will delete memory
  37. }
  38. void X::bar()
  39. {
  40.   ScopedLock safe_lock(l); // Lock will be released certainly
  41.   if (...)
  42.     if (...)
  43.       throw "ERROR";
  44.   // No need to call release here.
  45.   // Destructor of safe_lock will release the lock
  46. }

阅读(2810) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~