C++必須必須-RAII(リソース取得および初期化)

6314 ワード

RAII(リソース取得および初期化)、すなわちresource acquisition is initialization;彼は一部の人が「初期化すなわちリソース取得」(initialization is resource acquisition)と思っているわけではありません.これはメモリ、ファイルハンドル、ネットワーク接続、データベース接続、監査追跡などの重要なリソースにとって非常に重要です.
 
PAIIの基本技術原理は簡単で、重要なリソースの追跡を維持したい場合は、オブジェクトを作成し、リソースのライフサイクルとオブジェクトのライフサイクルを関連付けます.これにより,c++の複雑でベテランなオブジェクト管理メカニズムを用いてリソースを管理することができる.最も簡単な形式は、オブジェクトを構築すると、オブジェクトを構築してリソースが得られ、構造関数はこのリソースを解放します.
class Resoruce{...}//リソースクラス
class ResourceHandle
{
public:
     explicit ResourceHandle(Resource *aResource):r_(aReasource){}//リソースの取得
     ~ResourceHandle()
            {delete r_;}//リソースの解放
    Resource *get()
{return r_;}//リソースへのアクセス
private:
   ResourceHandle(const ResourceHandle &);
   ResourceHandle &operator = (const operator &);
   Resource   *r_;
};
void

 example_usage(

)

 {


    File logfile(

"logfile.txt"

)

;

 // open file (acquire resource)


    logfile.write

(

"hello logfile!"

)

;



// continue using logfile ... // throw exceptions or return without // worrying about closing the log; // it is closed automatically when // logfile goes out of scope
//...

if(IFeelLikeIt()) // NO problem here!
return;
//...
AnotherFunCall(); // exception thrown? No!

//destructor is called for logfile here
 }
ResourceHandle , , ,
。 return、 goto, 。
ResourceHandle , delete ResourceHandle , 。 ,
logfile , 。


背後にあるc++オブジェクト管理メカニズム
C++

 allow objects to be allocated on the stack

 and their scoping

 rules ensure that destructors are called when a local 
object's scope ends. By putting the resource release logic in the destructor, C++'s scoping provide direct support
 for RAII.
In this language, the only code that can be guaranteed to be executed after an exception is thrown are the destructors of
 objects residing on the stack . Resources therefore need to be tied to the lifespan of suitable objects in order to gain
automatic reclamation.

RAII is vital in writing exception-safe C++ code: to release resources before permitting exceptions to propagate
 (in order to avoid resource leaks) one can write appropriate destructors once rather than dispersing and duplicating
 cleanup logic between exception handling blocks that may or may not be executed.


RAII分類
RAIIは、リソース可変性とリソースソースの2つの特徴に基づいて分類できます.
リソースの可変性
カプセル化されたクラスがインスタンスに追加の機能を提供し、そのインスタンスに新しいリソースを付与できるようにする場合、このクラスが示す特徴は「可変RAI」と呼ばれ、そうでなければ「可変RAI」である.
可変RAIIは、最も使いやすいものです.単純なのは、この場合、新しい割り当てられたリソースでも、他のリソースをコピーしても、カプセル化クラスでリソースを指定する方法を提供する必要がないからです.このRAIIはまた,クラスの構造関数が常にカプセル化されたリソースが有効であると仮定できることを意味する.
これに対して、可変RAIIクラスを提供するには、デフォルトまたは空のコンストラクション関数、コピーコンストラクション関数、コピー付与操作、リソースを指定する方法のほとんど、またはすべてを実装する必要があります.最も重要なのは、このようなクラスは、構造関数およびclose()のような方法で、リソースを解放する前に、カプセル化されたリソースがnullであるかどうかを検出しなければならない.
 
リソースソース
RAIIを提供するクラスにとって、2つ目の重要な特徴は、どのような方法で管理されているリソースを取得するかです.std::stringに代表されるクラスでは、内部初期化されたRAIIを使用します.管理されているリソース、すなわち、文字を保存するためのメモリのバッファは、外部には永遠に表示されません.これとは異なりstd::auto_ptrに代表されるクラスは、外部初期化されたRAII動作を示します.管理されているリソースは、クライアントプログラム(別の方法で取得された後)を使用して渡されます.
内部初期化されたRAIIのパッケージクラスは、一般的には実現しやすいが、リソースを取得するメカニズムが予め定義されており、固定されているため、機能的にも制限されている.しかし、このようなクラスは使いやすく、あるいは、クライアントコードがリソースの漏洩を引き起こすエラーを犯す機会がほとんどないため、誤用されにくい.
 
Resource management without RAII
Finalizers
In Java , objects are not allocated on the stack and must be accessed through references; hence you cannot have automatic variables of objects that "go out of scope". Instead, all objects are dynamically allocated . In principle, dynamic allocation does not make RAII unfeasible per se; it could still be feasible if there were a guarantee that a "destructor"("finalize") method would be called as soon as an object were pointed to by no references (i.e., if the object lifetime management were performed according to reference counting ).
However, Java objects have indefinite lifetimes which cannot be controlled by the programmer, because, according to the Java Virtual Machine specification, it is unpredictable when the garbage collector will act. Indeed, the garbage collector may never act at all to collect objects pointed to by no references. Hence the "finalize"method of an unreferenced object might never be called or be called long after the object became unreferenced. Resources must thus be closed manually by the programmer, using something like the dispose pattern .
Reference Counting
Perl and CPython manage object lifetime by reference counting, making it possible to use RAII in a limited form. Objects that are no longer referenced are immediately released, so a destructor can release the resource at that time. However, object lifetime isn't necessarily bound to any lexical scope. One can store a reference to an object in a global variable, for example, thus keeping the object (and resource) alive indeterminately long. This makes it possible to accidentally leak resources that should have been released at the end of some scope. Also, in the case of Python, the actual garbage collection strategy is an implementation detail, and running with an alternative interpreter (such as IronPython or Jython) could result in the RAII implementation not working.

http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization
http://www.cppblog.com/jinq0123/archive/2008/05/20/RAII.html