C++【エラーと異常の処理】


一、プログラムのエラー
1.符号化エラー:コンパイルフェーズ
2.設計ミス:テスト段階
3.環境エラー:使用フェーズ
4.適用エラー:テストと使用フェーズ
二、エラー処理メカニズム
1.戻り値によるエラー処理
関数が実行中にエラーが発生した場合、関数の戻り値によって関数呼び出し者に通知されます.
malloc/fopen-有効なポインタが正常に返され、NULLが失敗しました
無効な値を返すと失敗します
0を返すと成功、-1を返すと失敗
1)利点:単純で、クラッシュを回避し、ローカルオブジェクトを分析する機会がある.
2)欠点:レイヤー毎に戻り値をチェックする
A->B->C
2.リモートジャンプによるエラー処理
1)利点:レイヤーごとに戻り値をチェックする必要がなく、エラー処理プロセスを簡略化する
2)欠点:ローカルオブジェクトは分析する機会がなく、メモリ漏れを形成する.
3.C++異常機構
注意:gotoは関数にまたがることはできません!
三、異常文法
例外を放出:
throw異常オブジェクト;
次のようになります.
throw -1;
throw 3.14;
throw "error";
class A { ... };
throw A ();
A a (...);
throw a;
例外の取得:
try {
異常を引き起こす文.
}
補足:
右かっこを実行し、プロファイルを保証します.
catch(異常タイプ1異常オブジェクト){
異常タイプ1に対する処理;
}
catch(異常タイプ2異常オブジェクト){
異常タイプ2に対する処理;
}
...
catch (...) {
他の異常タイプに対する処理;
}
次のようになります.
try {
  foo ();
  bar ();
  hum ();
}
catch (int ex) {
 //...
}
catch (double ex) {
}
catch (string& ex) {
}
catch (A& ex) {
}
catch (...) {
}
四、使用異常の注意事項
1.基本タイプの例外を投げ出し、例外オブジェクトの値で異なるエラーを区別します.
2.クラスタイプの例外を放出し、例外オブジェクトのタイプによって異なるエラーを区別します.
3.異常タイプでより多くの診断情報を携帯します.
4.異常説明
1)関数の定義と宣言には、関数が放出される可能性のある例外のタイプを示す例外説明句を追加できます.
2)関数がその異常説明以外の異常を投げ出した場合,その異常はプログラムに取り込めない.
3)取得されていないすべての例外は最終的にstd::unexpected()関数によって処理され、デフォルトではstd::terminate()関数が呼び出され、後者はabort()関数を呼び出してプロセスを終了します.
4)1つの関数に異常の説明がなければ、それはいかなる異常を投げ出すことができることを示し、throw()異常の説明があれば、それはいかなる異常を投げ出さないことを示す.
5)関数宣言と定義が別々の場合は、その宣言と定義の部分でまったく同じ例外説明を使用する必要があります.
6)サブクラス内のベースクラス虚関数のオーバーライドバージョンでは、ベースクラスバージョンよりも多くの例外が放出されることは説明できません.
5.異常を無視し、元の異常を放出し続け、新しい異常を放出し続ける
例外を無視:1つの関数が受信した例外に対してcatchを使用しないと、その例外は呼び出し元に投げ出され続け、catchになるまで、すべての関数がcatchを使用しないと、最終的にシステムによってキャプチャされ、プロセスが終了します.
元の異常を放出し続ける:throw;
新しい例外の放出を続行:catchでthrow新しい例外オブジェクト
五、構造関数に異常を投げ出す
1.コンストラクション関数で例外を放出することができ、場合によっては、コンストラクション中に発生したエラーのみを例外で表すことができます.
2.オブジェクトがコンストラクション中に例外を投げ出すと、そのオブジェクトは不完全にコンストラクションされ、不完全なコンストラクションのオブジェクトは、そのコンストラクション関数が実行されません.したがって、例外を投げ出す前に、動的に割り当てられたすべてのリソースを手動で解放する必要があります.これらのリソース構築関数のロールバックメカニズムは自動的に解放されないか、スマートポインタを使用します.
六、構造関数に異常を投げ出さないほうがいい
try {
  A a;
  a.foo ();
}
catch (...) {
  ...
}
異常な内部消化を引き起こす可能性があります.
七、標準ライブラリ異常
hexcump -c text.cpp
次のような例があります.
#include <iostream>
using namespace std;
//void foo (int i) throw (int, float) {
//void foo (int i) throw () {
void foo (int i) {
	if (i == 1)
		throw 10;
	if (i == 2)
		throw 3.14f;
	if (i == 3)
		throw "Hello, World !";
}
class A {
public:
	virtual void foo (void) throw () {}
};
class B : public A {
public:
	void foo (void) throw () {
		throw -1;
	}
};
int main (void) {
	try {
		foo (3);
	}
	catch (int ex) {
		cout << ex << endl;
	}
	catch (float ex) {
		cout << ex << endl;
	}
	catch (const char* ex) {
		cout << ex << endl;
	}
	catch (...) {
		cout << "    !" << endl;
	}
	return 0;
}
//
Hello, World !