カスタムC++例外処理


例1:exceptonから継承された例外クラスmyExceptionをカスタマイズする
C++標準では、に定義された異常クラスはすべてexception Classから派生し、この例も単純にexceptionによって継承され、tryセグメントに異常を投げ出して捕捉するだけである.コードは次のとおりです.
/*++ test.cpp
version:1.0
decript:define a exception class named myException
		derived from base class exception
		which is declared in <exception>
created:2011-08-14
author:	btwsmile
--*/
#include<exception>
#include<iostream>
using namespace std;

//customized exception class 'myException'
class myException:public exception
{
public:
	myException():exception("ERROR! Don't divide a number by integer zero.
") { } }; //entry of the application int main() { int x=100,y=0; try { if(y==0) throw myException(); else cout<<x/y; } catch(myException& me) { cout<<me.what(); } system("pause"); return 0; }

結果は以下の通りです:ERROR!Don't divide a number by integer zero. 任意のキーを押して続行してください.                                                  
明らかに、異常が捉えられた.ここで説明するのは、VCが異常処理クラスexceptionを拡張していることであり、この例でexception(「ERROR!...」)を使用できるのは、の初期化方法はこのような理由から、C++標準では許可されていません.
同時に、VCは標準に従っておらず、terminateとunexpectedを強力にサポートしており、構文のみを保持しているが、コンパイル実行時にサポートされていない.terminateとunexpectedを組み合わせてC++の異常処理をより深く理解するために、以下の例はDev cpp IDEで実現する.
例2:C++標準に従ってカスタム例外クラスmyExceptionを実現し、throw文を関数check()にカプセル化する
関連する変更は、タイトルに記載されているように、(1)ベースクラスのwhat()関数を書き換え、エラー情報を返す.(2)throw myException()をcheck()関数にカプセル化する.(3)check()関数がmyExceptionタイプの異常を投げ出すことを許可する.コードは次のとおりです.
/*++ test.cpp
version:1.1
decript:define a exception class named myException 
        according to C++ standard,
		derived from base class exception
		which is declared in <exception>
		!also,encapusulate throw into a function
created:2011-08-14
author:	btwsmile
--*/
#include<exception>
#include<iostream>
using namespace std;

//customized exception class 'myException'
class myException:public exception
{
public:
   const char* what()const throw()//#1 
   {
        return "ERROR! Don't divide a number by integer zero.
"; } }; void check(int y) throw(myException)//#2 { if(y==0) throw myException(); } //entry of the application int main() { int x=100,y=0; try { check(y); cout<<x/y; } catch(myException& me) { cout<<me.what(); } system("pause"); return 0; }

結果は例1と全く同じであった.なお、check()に続くthrowリストは、関数の放出を許可する異常タイプを示す.ここで疑問を抱かざるを得ないが,許されない異常タイプを投げ出したらどうなるのか.
例3:unexpected異常を投げ出す
check関数体の後のthrowリストは、放出を許可する異常タイプを規定しており、違反するとunexpectedがトリガーされます.unexpectedは、システムが自動的に呼び出すCALLBACK関数と見なすことができ、異なることに、手動で実行をトリガーすることもできます.本例の場合は前者に属する.コードは次のとおりです.
 
/*++ test.cpp
version:1.3
decript:define an unexpected excption handler,
        set it by using set_unexpected,
        modify the throw list of function check
created:2011-08-14
author:	btwsmile
--*/
#include<exception>
#include<iostream>
using namespace std;

//customized exception class 'myException'
class myException:public exception
{
public:
   const char* what()const throw()
   {
        return "ERROR! Don't divide a number by integer zero.
"; } }; void check(int y) throw()//#1 only int-type exception is permitted { if(y==0) throw myException(); } void myUnexpected() { cout<<"Unexpected exception caught!
"; system("pause"); exit(-1); } //entry of the application int main() { unexpected_handler oldHandler=set_unexpected(myUnexpected); int x=100,y=0; try { check(y); cout<<x/y; } catch(myException& me) { cout<<me.what(); } system("pause"); return 0; }

結果は次のとおりです.
Unexpected exception caught! 任意のキーを押して続行してください.                    
check関数のthrowリストは空です.つまり、任意のタイプの例外を放出することは許可されませんが、実際に異常が発生した場合、システムは無視できません.unexpected処理方法が呼び出されます.したがって,1つの関数throwリストを空に限定することはプログラマの注意に値することであり,特に注意が必要である.#1のコードをthrow(int)に変更するなどしても同様の結果が得られる.unexpected異常とは,関数体が異常タイプ範囲外の異常を放出することを許容することである.check関数の後ろにthrowがまったくない場合は、関数の任意のタイプの異常が許可されていることを示します.
例4:関数体が許容する異常を投げ出したが捕捉されなかった場合
関数checkのthrowリストに異常タイプmyExceptionがあり、y=0のときにmyExceptionタイプの異常を投げ出したが、catchに届かなかった場合、何が起こるかを考えてみましょう.
この質問に正式に答える前に、「catchに届かなかった」という意味を議論します.例えば、修正例3のコードは以下の通りである:(##は修正箇所)
/*++ test.cpp
version:1.4.1
decript:
        how to understand "exception not caucht"?
created:2011-08-14
author:	btwsmile
--*/
#include<exception>
#include<iostream>
using namespace std;

//customized exception class 'myException'
class myException:public exception
{
public:
   const char* what()const throw()
   {
        return "ERROR! Don't divide a number by integer zero.
"; } }; void check(int y) //any type of exception is permitted { if(y==0) throw myException(); } void myUnexpected() { cout<<"Unexpected exception caught!
"; system("pause"); exit(-1); } //entry of the application int main() { unexpected_handler oldHandler=set_unexpected(myUnexpected); int x=100,y=0; try { check(y); cout<<x/y; } catch(int &e) //##1 no catch sentence matches the throw type { cout<<e<<endl; } /* ##2 if add this part, any type which's not handler before will be caught catch(...) { cout<<"Unkown exception caught!
"; } */ system("pause"); return 0; }

コンパイルが実行されると、check関数から放出されたmyException異常が処理されないため、プログラムがエラーになります.デフォルトでは、例外が投げ出す処理されていないという問題が発生すると、abort()関数が自動的に呼び出され、プログラムを終了することができ、コンソールでこのようなヒントが表示されます:Thisアプリケーションhas requested the Runtime to terminate it in an unusual way.Please contact the application's support team for more information.
しかし、##2部分のコードを追加することができます.catch(...)任意のタイプの例外をスナップすることを示します.
注意:check関数が許可されていない異常タイプはcatch文の判断には入らないのでcatch(...)unexpected exceptionには機能しません.
まだ##2部分がない場合を考えています.前述したように、abort()関数終了プログラムが自動的に呼び出されます.実際には、unexpectedと同様にterminateをトリガーし、terminateの処理方法をカスタマイズすることができます.terminate文法的にもunexpectedに近い.コードを次のように変更します.
/*++ test.cpp
version:1.4.2
decript:
        how to understand "exception not caucht"?
created:2011-08-14
author:	btwsmile
--*/
#include<exception>
#include<iostream>
using namespace std;

//customized exception class 'myException'
class myException:public exception
{
public:
   const char* what()const throw()
   {
        return "ERROR! Don't divide a number by integer zero.
"; } }; void check(int y) //any type of exception is permitted { if(y==0) throw myException(); } void myUnexpected() { cout<<"Unexpected exception caught!
"; system("pause"); exit(-1); } void myTerminate() //##1 set it be the terminate handler { cout<<"Unhandler exception!
"; system("pause"); exit(-1); } //entry of the application int main() { unexpected_handler oldHandler=set_unexpected(myUnexpected); terminate_handler preHandler=set_terminate(myTerminate); int x=100,y=0; try { check(y); cout<<x/y; } catch(int &e) //no catch sentence matches the throw type { cout<<e<<endl; } system("pause"); return 0; }

結果は次のとおりです.
Unhandler exception! 任意のキーを押して続行してください.    
結論:C++は異常処理に友好的なサポートを提供した.
ユーザーは例外タイプをカスタマイズできます.例外タイプは制限されません.int、doubleなどの組み込みデータタイプでもカスタムクラスでもC++の例外クラスから継承できます.例1はexceptionから派生する方法を採用した.
また、関数を定義するときに、関数体が放出する例外のタイプを明示的に指定できます.暗黙的な場合、デフォルトでは関数が任意のタイプの例外を放出できます.throw文を増やして異常タイプを制限できるものがあります.特にthrow()は、関数が任意のタイプの異常を放出することを許さないことを示す.throwリストに規定された例外タイプに違反した場合、unexpected hanlderを呼び出して処理し、unexpected例外処理方法をカスタマイズできます.例2および例3について説明した.
関数体throwリストに対する正当な異常が投げ出されたが、プログラムキャプチャ処理されていない場合、terminate handlerが呼び出されます.デフォルトでは、abort()関数終了プログラムを簡単に呼び出すだけで、terminate処理方法をカスタマイズできます.例4で説明した.