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]MotivationResources 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.
- void foo ()
- {
- char * ch = new char [100];
- if (...)
- if (...)
- return;
- else if (...)
- if (...)
- else
- throw "ERROR";
-
- delete [] ch; // This may not be invoked... memory
- }
- void bar ()
- {
- lock.acquire();
- if (...)
- if (...)
- return;
- else
- throw "ERROR";
-
- lock.release(); // This may not be invoked...
- }
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 CodeThe 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.
- // Private copy constructor and copy assignment ensure classes derived
- // from class NonCopyable cannot be copied.
- class NonCopyable
- {
- NonCopyable (NonCopyable const &); // private copy constructor
- NonCopyable & operator = (NonCopyable const &); // private assignment operator
- };
- template <class T>
- class AutoDelete : NonCopyable
- {
- public:
- AutoDelete (T * p = 0) : ptr_(p) {}
- ~AutoDelete () throw() { delete ptr_; }
- private:
- T *ptr_;
- };
-
- class ScopedLock : NonCopyable// Scoped Lock idiom
- {
- public:
- ScopedLock (Lock & l) : lock_(l) { lock_.acquire(); }
- ~ScopedLock () throw () { lock_.release(); }
- private:
- Lock& lock_;
- };
-
- void foo ()
- {
- X * p = new X;
- AutoDelete<X> safe_del(p); // Memory will not leak
- if (...)
- if (...)
- return;
-
- // No need to call delete here.
- // Destructor of safe_del will delete memory
- }
- void X::bar()
- {
- ScopedLock safe_lock(l); // Lock will be released certainly
- if (...)
- if (...)
- throw "ERROR";
- // No need to call release here.
- // Destructor of safe_lock will release the lock
- }
阅读(2810) | 评论(0) | 转发(0) |