カスタムC++異常処理の例を示します。

9643 ワード

カスタムC++異常処理の例を示します。
例1:exceptonから継承される異常なクラスmyExceptionをカスタマイズします。
C++標準において、「stdexcept」に定義されている異常クラスはいずれも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を実現し、関数check()にthrow文をパッケージ化した変更はタイトル通りであり、(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を投げる異常
関数体をチェックした後の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処理方法を呼び出します。したがって、関数の一つである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 application 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()関数を呼び出してプログラムを終了します。実際、それがトリガされたのはterminateで、unexpectedのように、まだカスタム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 halderを呼び出して処理します。unexpected異常処理方法をカスタマイズできます。例2と例3はそれらを説明した。
関数のthrowリストに対して合法的な異常が投げ出されても、プログラムによって処理されていない場合、システムはterminate handlerを呼び出して処理します。デフォルトの場合は、単にabort()関数終了プログラムを呼び出すだけで、同様にterminate処理方法をカスタマイズすることができます。例4はそれを説明した。
疑問があれば、メッセージをお願いします。あるいは、当駅のコミュニティで交流して討論してください。ありがとうございます。