c++RAIIメカニズム

2714 ワード

次の2つのブログから転記します.
https://blog.csdn.net/wozhengtao/article/details/52187484
https://blog.csdn.net/doc_sgl/article/details/43028009
RAIIの本質的な内容は対象で資源を代表して、資源を管理する任務を管理対象の任務に転化して、資源の獲得と釈放を対象の構造と構造に対応して、それによって対象の生存期間内に資源が終始有効であることを確保して、対象が廃棄する時資源は必ず釈放される.はっきり言って、オブジェクトを持って、リソースを持って、オブジェクトは、リソースはあります.そのため、RAIIメカニズムは資源管理を行う有力な武器であり、C++プログラマーがRAIに頼って書いたコードは簡潔で優雅であるだけでなく、異常な安全を実現した.以降のプログラミングの実際では、RAIIメカニズムを使って、自分のコードをもっときれいにすることができます.
 
1.RAIIテクノロジーとは?私たちはC++でnewをよく使ってメモリ空間を申請していますが、deleteが申請を回収する空間を忘れがちで、メモリオーバーフローを起こしやすいので、RAII技術が誕生し、このような問題を解決します.RAII(Resource Acquisition Is Initialization)メカニズムはBjarne Stroustrupが最初に提案したものであり,オブジェクトライフサイクルを利用してプログラムリソースを制御するメモリ、ファイルハンドル、ネットワーク接続、反発などの簡単な技術です.関数の内部にあるメンバーの一部がスタック空間に配置されていることを知っています.関数が戻ると、これらのスタックのローカル変数はすぐに空間を解放します.そこで、Bjarne Stroustrupは、リソース解放コードを実行できる場所がこのプログラムセグメントであることを考えています.(スタック)に配置されたオブジェクトの構造関数です.stack windingはそれらの構造関数がすべて実行されることを保証するからです.RAIDはスタック内の変数のこの特徴を利用しています.RAIDの一般的なやり方は、オブジェクトの構造時にリソースを取得し、次にリソースへのアクセスを制御してオブジェクトのライフサイクル内で常に有効にし、最後にオブジェクトの構造時にリソースを解放します.これにより、実際には、スタック空間に格納されたローカルオブジェクトにリソースを管理する責任を負います.
このアプローチには,(1)リソースを明示的に解放する必要がないという2つの大きな利点がある.(2)このようにして,オブジェクトに必要なリソースはそのライフタイム内に常に有効である.
2.実戦応用
2.1簡単な例:ポインタ申請空間、解放空間
void Func()
{
  int *ip = new int[10];
  ...//operations
  ...//operations
  ...//operations
  delete[] ip;//if not free mem, memory overflow
}

RAID技術を使用した後:
template
class My_Pointer
{
public:
   My_Pointer(PointerType* _ptr, size_t sz)
   {
        _ptr = new PointerType[sz];
        m_ptr = _ptr;
   }
   ~My_Pointer()
   {
        delete []m_ptr;
   }
protected:
   PointerType    m_ptr;
}

2.2 scope lock(ローカルロック技術)多くの場合、マルチスレッド間のデータ同期を実現するためにmutex、critical section、event、singalなどの技術を使用します.しかし、使用中は様々な理由で、時には、我々は一つの問題に直面する:Unlockロックを解除することを忘れたため、デッドロック現象が発生する.RAIIを採用すればこの問題をうまく解決することができ、ロックを解除する問題を心配する必要はない.例コードは以下の通りである:My_scope_lockは局所ロックを実現するテンプレートクラスである.LockTypeは具体的なロッククラスを代表する.例えばmutexに基づいてmutex_lockクラスを実現する.
template
class My_scope_lock
{
   public:
   My_scope_lock(LockType& _lock):m_lock(_lock)
   { 
         m_lock.occupy();
   }
   ~My_scope_lock()
   {
        m_lock.relase();
   }
   protected:
   LockType    m_lock;
}

使用時:
//global vars
int counter = 0;
void routine();
mutex_lock  m_mutex_lock;
 
void routine()
{
    My_scope_lock l_lock(m_mutex_lock);
    counter++;
    ...//others...
}

上記の例クラスに基づいて、このような例を多く出すことができます.ファイルを読み書きするときにファイルを閉じることを忘れがちな場合は、RAIIテクノロジーを借りれば、このようなエラーを回避できます.また、データベースへのアクセスや、データベース接続の切断を忘れた場合なども、RAIDテクノロジーを利用して解決できます.