Essential C++学習ノート第七章

6169 ワード

異常処理
この章はよくあるバグをどうやって解決するかを教えてくれると思いますが、結果は主にコードの異常をフォローして出力します。これらのコードは特にJavaのように感じられます。
異常を投げるthrowというコマンドであり、一例を示している。
inline void Traingular_iterator::
check_integrity()
{
   if (_index>=Triangular::_max_elems)
      throw iterator_overflow(_index,Trinagular::_max_elems);
   if (_index>=Triangular::_elems.size())
      Triangular::gen_elements(_index+1);
};

//iterator_overflow    
class iterator_overflow{
public:
   iterator_overflow(int index, int max)
           : _index(index), _max(max){}
   //...
};
ここだけ見たらちょっと変な感じがするかもしれませんが、投げ出したらどうですか?与えられたcatchに相当する入力値を実際に投げます。次のセクションを見てください
捕獲異常
それとも先に例をあげますか?
bool some_function()
{ 
   //...
   catch(iterator_overflow &iof){
       iof.what_happened(log_file);
       status = false;
   }
   //...
}
ここでのcatchは、ちょうど前のthrowからの入力値の構造体タイプである。もちろんcatchケンは一つ以上ではなく、複数のcatchが出現した場合には。throwが発生した場合、プログラムはthrowのタイプに従って、catchの入力に適合しているかどうかを逐次比較します。
また、catchにはthrowが嵌め込まれても良いし、任意のタイプの異常を取り込むためには、入力部分を省略記号としても良い。
catch(...)
{
   log_message("exception of unknown type");
}
精錬異常tryの使用を紹介します。最初の3つのセクションは一緒に見ると分かりやすくなります。まず例を示します。
bool has_elem(Triangular_iterator first,
              Triangular_iterator last, int elem)
{
   bool status = true;

   try
   {
      while(first!=last)
      {
         if(*first == elem)
            return status;
         ++first;
      }
   }
   catch(iterator_overflow &iof)
   {
      log_message(iof.what_happened());
      log_message("check if iterators address same container");
   }

   status = false;
   return status;
}

//        
inline int Triangular_iterator::
operator*()
{
   check_integrity();
   return Triangular::_elems[_index];
}

inline void Triangular_iterator::
check_integrity()
{
   if (_index>=Triangular::_max_elems)
      throw iterator_overflow(_index, Triangular::_max_elems);
   //...
}

まず、何が起こったかを説明します。has_elem関数のtryには、エラーが発生する可能性があるコードがあります。一方、*first演算子は既に重載されており、重載された関数の*は、プログラムの正確さを確認する。check_integrity()のこの関数にエラーが発生したら、check_integrity()の前のセクションで定義された構造体throwが存在する。
プログラムの実行規則は、もし異常が発生したら、まずiterator_overflow内にあるかどうかを判断し、もしそうであれば、異常な処理能力、すなわち対応するtryがあるかどうかを判断する。異常があると処理され、プログラムは続行されます。catch内に異常がない場合、現在の関数コードセグメントは直接に飛び出します。
プログラム実行にエラーが発生したら、これは本当に投げ出されます。プログラムは、現在の関数tryにおいてthrowではないが、残念ながらそうではないので、プログラムは、最初のifだけ実行されています。以下は実行されていません。関数check_integrity()はそのまま飛び出してしまいます。tryオペレータは、ここでcheck_integrity()を受信したのと同じです。これから呼び出された関数だけではないですが、ここでは*もないと検索されました。
return Triangular::_elems[_index];
実行しません。次いで、最外層に戻る関数throwにおいて、異常がtryの内にあり、ちょうど*が要求を満たすと、has_elem()の中のコンテンツが実行され、その後も下方向に動作し続ける。tryの中にいれば、対応するcatchが見つからないですか?依然として飛び出すのです。catch関数に戻ってきたとしますか?それとも適当なtryが見つかりませんでしたか?プログラムは標準ライブラリcatchを呼び出し、その実行結果は中断プログラムである。mainおよびcatchおよびterminate()は、どのように配置されているかについては、非常に議論に値する。文中で大きな議論が行われましたが、ここでは述べません。
また、違いが必要なのは、C++の各異常に対応するtryを見つけることができることである。ただし、catchおよびthrowのようなハードウェアエラーは、C++の範囲内ではない。
ローカルリソース管理
どういう意味ですか?throw出願のメモリ空間の解放問題である。まずコードを見ます。
extern Mutex m;
void f()
{
   int *p = new int;
   m.acquire();

   process(p);

   m.release();
   delete p;
}
正常に実行された場合、segmentation faultおよびbus errorのメモリは最終的に解放される。しかし、newにエラーが発生した場合、プログラムは最終的にメモリを解放していない可能性があります。直感的な解決方法は、対応するpにメモリを解放するコードセグメントを書き込むことであるが、より良い解決策がある。つまり、リソース管理という手法は、実際には初期化段階でリソース要求を行うものである。
名前が高いと聞いていますが、主に二つのテクニックです。一つは、コンストラクタとコンストラクタを用いて初期化し、すべての変数を解放することである。たとえば:
class MutexLock{
public:
   MutexLock(Mutex m) : _lock(m)
   { lock.acquire();}

   ~MutexLock(){lock.acquire();}
private:
   Mutex &_lock;
};
このとき、mタイプのオブジェクトを申請すれば、異常が発生しても、構文関数は必ず実行され、メモリは必ず解放される。
第二に、関数ライブラリprocessを介してである。具体的な使い方は:
auto_ptr p(new int);
実際にはcatchMutexLockタイプのクラス実装に相当するが、このクラスはまたオペレータをリロードし、ベースの動作が元の変数と同じになるように、例えば:
auto_ptr aps(new string("vermeer"));
string *ps = new string("vermeer");

if (( aps->size() == ps->size()) && (*aps==*ps))
//...
ここでの#include およびnewは、直接に相互に値を割り当てることができる。
標準異常
異常を受けたら、異常が発生した変数を操作したいです。異常系(exception classis hierarchy)を借りる必要があります。このクラスは抽象類intに基づいています。一方、抽象類は*aps虚数関数を宣言しています。したがって、各異常クラスシステムにおける派生クラスは、*psの具体的な実装を提供しなければならない。たとえば:
#include 

class iterator_overflow: public exception{
public:
   iterator_oveflow(int index, int max)
       : _index(index), _max(max)
       {}

   int index() { return _index;}
   int max()   { return _max; }

   const char* what() const;

private:
   int _index;
   int _max;
};
同時に、継承クラスの規則exceptionの入力値を利用して、虚数種類のタイプを書くだけで、このライブラリの中のすべてのエラータイプを一度ずつではなく含められます。
catch(const exception &ex)
{
   cerr << ex.what() <
最後の文では、what()の実施形態が示されている。
#include 
#include 

const char*;
iterator_overflow::
what() const
{
   ostringstream ex_msg;
   static string msg;

   ex_msg << ...

   //            string
   msg = ex_msg.str();

   //   const char*    
   return msg.c_str();
}
ここで強調したいのはconst char *がメモリ内の出力動作を提供するためであり、これはwhat()ヘッダのファイルを呼び出す必要がある。catchは、what()に変換することができる。さらにostringstream classは、sstreamを必要な.str()に変換することができる。
終わったら花を散らします。収穫が多いです。