今日のレッスン-[例外処理] C ++標準例外処理:原則+方法

例外は、プログラムの実行中に発生する問題です。C ++例外は、ゼロ除算の試行など、プログラムの実行中に発生する特別な条件です。

 

関数の例外宣言のリスト

プログラムの可読性と保守性を向上させ、プログラマーが関数の使用時に関数がスローする可能性のある例外を確認できるようにするために、C ++では、関数が宣言および定義されたときにスローできる例外を追加できます。例外のリストは次のように記述されます。次のとおりです。

void func() throw (int, double, A, B, C);

または

void func() throw (int, double, A, B, C){...}

上記の記述は、funcがint、double、A、B、およびCの3種類の例外をスローする可能性があることを示しています。例外宣言リストは、関数が宣言されたとき、または関数が定義されたときに書き込むことができます。両方の場所に書く場合、2つの場所は同じである必要があります。

例外宣言リストが次のように記述されている場合:

void func() throw ();

これは、func関数が例外をスローしないことを意味します。

関数がスローできる例外のタイプを説明していない場合、関数は任意のタイプの例外をスローできます。

関数が例外宣言リストにない例外をスローした場合、コンパイル時にエラーは発生しませんが、実行時に、Dev C ++によってコンパイルされたプログラムにエラーが発生します。VisualStudio2010でコンパイルされたプログラムは発生しません。エラー。宣言リストは実際的な効果はありません。

例外は、プログラムの制御を移す方法を提供します。C ++の例外処理には、try、catch、throwの3つのキーワードが含まれます。

  • throw: 問題が発生すると、プログラムは例外をスローします。これは、throw キーワードを使用して実行され ます。
  • catch: 問題を処理する場所で、例外ハンドラーを介して例外をキャッチします。catch キーワードは、例外をキャッチするために使用されます。
  • try: try ブロックのコードは、アクティブ化される特定の例外を識別します。通常、その後に1つ以上のキャッチブロックが続きます。

ブロックが例外をスローした場合、例外をキャッチする方法では、  try キーワード と catchキーワードを使用します。例外をスローする可能性のあるコードをtryブロックに配置します。tryブロック内のコードは保護コードと呼ばれます。try / catchステートメントを使用するための構文は次のとおりです。

try
{
   // 保护代码
}catch( ExceptionName e1 )
{
   // catch 块
}catch( ExceptionName e2 )
{
   // catch 块
}catch( ExceptionName eN )
{
   // catch 块
}

try ブロックがさまざまな状況でさまざまな例外をスローする場合は、 複数のcatch ステートメントをリストして、さまざまなタイプの例外をキャッチすることができ ます。

C ++例外処理の基本構文

C ++は、throwステートメントとtry ... catchステートメントを介して例外処理を実装します。throwステートメントの構文は次のとおりです。

throw  表达式;

このステートメントは例外をスローします。例外は、値型が基本型またはクラスである式です。

try ... catchステートメントの構文は次のとおりです。

try {
    语句组
}
catch(异常类型) {
    异常处理代码
}
...
catch(异常类型) {
    异常处理代码
}

複数のキャッチが存在する可能性がありますが、少なくとも1つです。

次の{}のtryとコンテンツを「tryブロック」と呼び、次の{}のcatchとコンテンツを「catchブロック」と呼びたい場合があります。

例外をスローする

throw ステートメントを使用して、コードブロック内の任意の場所に例外をスローできます throwステートメントのオペランドは任意の式にすることができ、式の結果のタイプによって、スローされる例外のタイプが決まります。

以下は、ゼロ除算を試みたときにスローされる例外の例です。

double division(int a, int b)
{
   if( b == 0 )
   {
      throw "Division by zero condition!";
   }
   return (a/b);
}

キャッチ例外

catch ブロックはtry ブロックの後に続き、 例外をキャッチします。キャッチする例外のタイプを指定できます。これは、catchキーワードの後の括弧内の例外宣言によって決定されます。

try ... catchステートメントの実行プロセスは次のとおりです。

  • tryブロック内のステートメントを実行します。実行中に例外がスローされない場合、最後のcatchブロックの後のステートメントは実行後に実行され、catchブロック内のすべてのステートメントは実行されません。
  • tryブロックの実行中に例外がスローされた場合は、例外がスローされた後、すぐに最初の「例外タイプ」とcatchブロックのスローされた例外タイプにジャンプします(例外は「catchブロックによってキャッチ」と呼ばれます」 )、実行後、最後のcatchブロックにジャンプして実行を続行します。
try
{
   // 保护代码
}catch( ExceptionName e )
{
  // 处理 ExceptionName 异常的代码
}

上記のコードは 、タイプExceptionNameの例外をキャッチし ます以下に示すように、catchブロックでtryブロックによってスローされたあらゆるタイプの例外を処理する場合は、例外宣言の括弧内に省略記号...を使用する必要があります。

try
{
   // 保护代码
}catch(...)
{
  // 能处理任何异常的代码
}

以下は例です。ゼロで除算された例外をスローし、catchブロックで例外をキャッチします。

#include <iostream>
using namespace std;
 
double division(int a, int b)
{
   if( b == 0 )
   {
      throw "Division by zero condition!";
   }
   return (a/b);
}
 
int main ()
{
   int x = 50;
   int y = 0;
   double z = 0;
 
   try {
     z = division(x, y);
     cout << z << endl;
   }catch (const char* msg) {
     cerr << msg << endl;
   }
 
   return 0;
}

const char *型の 例外をスローするため、 例外をキャッチするときは、catchブロックでconst char *を使用する必要があります。上記のコードをコンパイルして実行すると、次の結果が生成されます。

Division by zero condition!

スローされた例外がcatchブロックによってキャッチされない場合、たとえば、catch(int e)をcatch(char e)に変更します。入力nが0の場合、スローされた整数例外はcatchブロックによってキャッチされません。例外は処理されないため、プログラムはすぐに終了し、try ... catchの後のコンテンツは実行されません。

C ++標準例外

C ++は、その中で定義されている一連の標準例外を提供します。これらの標準例外をプログラムで使用できます。これらは、以下に示すように、親クラスと子クラスの階層で編成されています。

 

次の表は、上記の階層の各例外の説明です。

 

上記の例外クラスを以下に紹介します。このセクションのプログラムの出力は、Visual Studio2010に基づいています。DevC++によってコンパイルされたプログラムの出力は異なります。

1)bad_typeid

typeid演算子を使用する場合、そのオペランドがポリモーフィッククラスへのポインターであり、ポインターの値がNULLの場合、この例外がスローされます。

2)bad_cast

dynamic_castを使用してポリモーフィック基本クラスオブジェクト(または参照)から派生クラスの参照にキャストする場合、変換が安全でない場合、この例外がスローされます。プログラム例は次のとおりです。

#include <iostream>
#include <stdexcept>
using namespace std;
int main()
{
    try {
        char * p = new char[0x7fffffff];  //无法分配这么多空间,会抛出异常
    }
    catch (bad_alloc & e)  {
        cerr << e.what() << endl;
    }
    return 0;
}

プログラムの出力は次のとおりです。

Bad dynamic_cast!

PrintObj関数で、bがdynamic_castを介してDerivedオブジェクトを参照しているかどうかを確認します。参照している場合は、そのPrintメンバー関数を呼び出します。そうでない場合は、例外をスローし、Derived :: Printを呼び出さないでください。

3)bad_alloc

new演算子を使用した動的メモリ割り当て中に、十分なメモリがない場合、この例外がスローされます。プログラム例は次のとおりです。

#include <iostream>
#include <stdexcept>
using namespace std;
int main()
{
    try {
        char * p = new char[0x7fffffff];  //无法分配这么多空间,会抛出异常
    }
    catch (bad_alloc & e)  {
        cerr << e.what() << endl;
    }
    return 0;
}

プログラムの出力は次のとおりです。

bad allocation
ios_base::failure

デフォルトの状態では、入力ストリームオブジェクトと出力ストリームオブジェクトはこの例外をスローしません。ストリームオブジェクトの例外メンバー関数でいくつかのフラグビットが設定されている場合、ファイルを開くときにエラーが発生したとき、または入力ストリーム内のファイルの終わりが読み取られたときに、この例外がスローされます。ここでは繰り返しません。

4)out_of_range

ベクトルまたは文字列のatメンバー関数を使用して添え字に基づいて要素にアクセスする場合、添え字が範囲外の場合、この例外がスローされます。例えば:

#include <iostream>
#include <stdexcept>
#include <vector>
#include <string>
using namespace std;
int main()
{
    vector<int> v(10);
    try {
        v.at(100) = 100;  //拋出 out_of_range 异常
    }
    catch (out_of_range & e) {
        cerr << e.what() << endl;
    }
    string s = "hello";
    try {
        char c = s.at(100);  //拋出 out_of_range 异常
    }
    catch (out_of_range & e) {
        cerr << e.what() << endl;
    }
    return 0;
}

プログラムの出力は次のとおりです。

invalid vector <T> subscript
invalid string position

v.at(100)をv [100]に置き換え、s.at(100)をs [100]に置き換えると、プログラムは例外を発生させません(ただし、プログラムがクラッシュする可能性があります)。atメンバー関数は、範囲外の添え字を検出して例外をスローしますが、operator []は検出しないためです。atに対する演算子[]の利点は、添え字が範囲外かどうかを判断する必要がないため、実行速度が速くなることです。

新しい例外を定義する

例外 クラスを継承してオーバーロードすることにより、新しい例外定義でき ます。次の例は、std :: exceptionクラスを使用して独自の例外を実装する方法を示しています。

#include <iostream>
#include <exception>
using namespace std;
 
struct MyException : public exception
{
  const char * what () const throw ()
  {
    return "C++ Exception";
  }
};
 
int main()
{
  try
  {
    throw MyException();
  }
  catch(MyException& e)
  {
    std::cout << "MyException caught" << std::endl;
    std::cout << e.what() << std::endl;
  }
  catch(std::exception& e)
  {
    //其他的错误
  }
}

これにより、次の結果が生成されます。

MyException caught
C++ Exception

ここで、what() は、すべてのサブ例外クラスによってオーバーロードされた例外クラスによって提供されるパブリックメソッドです。これにより、例外の理由が返されます。

C / C ++を学びたいと思っている友達、考えがなく、学び始める方法がわからない場合は、グループに参加してください:1151395975、私に従って学習してください。また、無料の学習資料をたくさん受け取ることができます。

 

おすすめ

転載: blog.csdn.net/Python6886/article/details/112173826