Essential C++学習ノート第七章
6169 ワード
異常処理
この章はよくあるバグをどうやって解決するかを教えてくれると思いますが、結果は主にコードの異常をフォローして出力します。これらのコードは特にJavaのように感じられます。
異常を投げる
捕獲異常
それとも先に例をあげますか?
また、
プログラムの実行規則は、もし異常が発生したら、まず
プログラム実行にエラーが発生したら、これは本当に投げ出されます。プログラムは、現在の関数
また、違いが必要なのは、C++の各異常に対応する
ローカルリソース管理
どういう意味ですか?
名前が高いと聞いていますが、主に二つのテクニックです。一つは、コンストラクタとコンストラクタを用いて初期化し、すべての変数を解放することである。たとえば:
第二に、関数ライブラリ
標準異常
異常を受けたら、異常が発生した変数を操作したいです。異常系(exception classis hierarchy)を借りる必要があります。このクラスは抽象類
終わったら花を散らします。収穫が多いです。
この章はよくあるバグをどうやって解決するかを教えてくれると思いますが、結果は主にコードの異常をフォローして出力します。これらのコードは特に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);
実際にはcatch
のMutexLock
タイプのクラス実装に相当するが、このクラスはまたオペレータをリロードし、ベースの動作が元の変数と同じになるように、例えば: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()
に変換することができる。終わったら花を散らします。収穫が多いです。