C++ でメッセージを使用して例外をスローする

Jay Shaw 2023年10月12日
  1. 標準 C++ 例外を使用したメッセージ付きの例外のスロー - 無効な引数
  2. 標準 C++ 例外を使用してメッセージ付きの例外をスローする - ネストされた例外
  3. ランタイム エラーを使用して C++ のメッセージで例外をスローする
  4. まとめ
C++ でメッセージを使用して例外をスローする

この記事では、C++ で変数メッセージを使用して例外をスローする方法について説明します。 例外スローは、クラッシュやオーバーフローを回避するためにプログラムの制御を移すプロセスです。

問題が発生する可能性のあるプログラム内に例外スローを配置することによって実行されます。 C++ にはいくつかの例外処理キーワードがありますが、この記事では可変メッセージで例外をスローする方法について説明します。

標準 C++ 例外を使用したメッセージ付きの例外のスロー - 無効な引数

このプログラムは、C++ の標準例外からの 無効な引数 例外を使用して、可変メッセージで例外をスローします。

パッケージのインポート

このプログラムは、標準 C++ 例外を含めるための stdexcept と、入出力操作のための iostream という 2つのインポート パッケージを使用します。

例外をスローするメソッド

このプログラムは、入力として提供された 2つの数値を比較する関数を定義し、負の入力が検出された場合に例外ケースをスローします。 ここでは、標準例外 std::invalid_argument が使用されます。

このプログラムでは、var_avar_b という 2つの整数値をパラメーターとして持つメソッド compare が定義されています。 これは、if を使用して負の数 (a、b、またはその両方) をチェックし、そうであれば例外をスローします。

if (var_a < 0 || var_b < 0) {
  throw std::invalid_argument("Negative value encountered");

主な方法

main メソッドは try-catch 例外キーワードを使用して、有効な例外をスローします。

例外処理は、try ブロック内でメソッド compare を呼び出すことによって実行されます。 入力 (-1,3) は負の数であるため、try ブロックは引数を catch ブロックに送信し、可変メッセージで例外をスローしてメッセージを出力します。

#include <iostream>
#include <stdexcept>

using namespace std;

int check_neg(int var_a, int var_b) {
  if (var_a < 0 || var_b < 0) {
    throw std::invalid_argument("Negative value encountered");
  }
  return 0;
}

int main() {
  try {
    compare(-1, 3);
  } catch (const std::invalid_argument& e) {
    std::cout << "booh!";
  }
}

出力:

booh!
--------------------------------
Process exited after 0.006709 seconds with return value 0
Press any key to continue . . .

標準 C++ 例外を使用してメッセージ付きの例外をスローする - ネストされた例外

例外を互いにネストして、例外スローの複数のメッセージを連続して表示できます。 このセクションのプログラムは、ネストされた例外でエラー メッセージをラップし、発生するたびに変数メッセージを含む例外をスローして、それらを一緒に表示します。

パッケージのインポート

このプログラムで使用されるインポート パッケージは次のとおりです。

  • iostream
  • stdexcept
  • exception
  • string
  • fstream

メンバー メソッド

このプログラムには、print_exceptionopen_file、および run の 3つのメンバー関数があります。

メソッド print_exception:

これには 2つのパブリック パラメータがあります - std::exception& exstd 例外をキャッチし、整数変数 stage は値 0 で初期化されます。 メソッド内で、最初の行 std::cerrEncountered Exception: というエラー メッセージを出力するために使用されますが、std::string(level,'') を使用してネストのレベルに配置されます。

エラー メッセージの後に ex.what が続きます。ここで、exstd::exception のオブジェクトであり、ex.what は発生したエラーに関する説明文字列を返します。

try ブロックは std::rethrow_if_nested(e) を使用して例外をスローしますが、これは std オブジェクト ex がネストされた例外から派生した場合のみであり、このプログラムでそれを行います。

catch ブロックは、std オブジェクト nestedException を使用して、stage の値を 1 増やしながら、再帰的に自身を再度呼び出します。catch(...) メソッドは、すべての例外をキャッチします。

void print_exception(const std::exception& ex, int level = 0) {
  std::cerr << std::string(level, ' ') << "Encountered Exception: " << ex.what()
            << '\n';
  try {
    std::rethrow_if_nested(ex);
  } catch (const std::exception& nestedException) {
    print_exception(nestedException, stage + 1);
  } catch (...) {
  }
}

上記のコードでは、例外の説明文字列を出力しようとしています。 関数がネストされていることを検出すると、保持している例外の説明を再帰的に出力します。

メソッド open_file:

この関数には単一の文字列パラメーター std::string& s があり、これは std::string オブジェクトを作成し、エイリアス s をそれに転送します。

try-catch ブロックはファイルの読み取りを試み、ファイルを読み込めない場合に例外をキャッチし、ネストされた関数でラップします。

void open_file(const std::string& s) {
  try {
    std::ifstream file(s);
    file.exceptions(std::ios_base::failbit);
  } catch (...) {
    std::throw_with_nested(std::runtime_error("Couldn't open " + s));
  }
}

メソッド run():

メソッド void run()try ブロック内でメソッド open_file を呼び出します。 catch(...) ブロックは、std::throw_with_nested によって発生するすべての例外をキャッチします。

e と現在処理中の例外を組み合わせた例外を発生させます。

現在処理中の例外が外部例外になり、e がネストされた例外になります。 "run() failed" が最後に出力されるメッセージです。

void run() {
  try {
    open_file("nonexistent.file");
  } catch (...) {
    std::throw_with_nested(std::runtime_error("run() failed"));
  }
}

メソッド int main():

main メソッドは try ブロック内で関数 run() を呼び出しますが、catch ブロック内では、プログラムは e をパラメーターとして渡しながらメソッド print_exception を呼び出します。

変数メッセージで例外をスローする関数を実行し、ネストされた形式でキャッチされた例外を出力し、例外がスローされるたびにカスタム メッセージを表示します。

int main() {
  try {
    run();
  } catch (const std::exception& e) {
    print_exception(e);
  }
}

完全なコード:

#include <exception>
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <string>

void print_exception(const std::exception& ex, int stage = 0) {
  std::cerr << std::string(stage, ' ') << "Encountered Exception: " << ex.what()
            << '\n';
  try {
    std::rethrow_if_nested(ex);
  } catch (const std::exception& nestedException) {
    print_exception(nestedException, stage + 1);
  } catch (...) {
  }
}

void open_file(const std::string& s) {
  try {
    std::ifstream file(s);
    file.exceptions(std::ios_base::failbit);
  } catch (...) {
    std::throw_with_nested(std::runtime_error("Couldn't open " + s));
  }
}

void run() {
  try {
    open_file("nonexistent.file");
  } catch (...) {
    std::throw_with_nested(std::runtime_error("run() failed"));
  }
}

int main() {
  try {
    run();
  } catch (const std::exception& e) {
    print_exception(e);
  }
}

出力:

exception: run() failed
 exception: Couldn't open nonexistent.file
  exception: basic_ios::clear

--------------------------------
Process exited after 0.05326 seconds with return value 0
Press any key to continue . . .

ランタイム エラーを使用して C++ のメッセージで例外をスローする

カスタム クラスを使用して、ソース ファイルのパスとこのエラーがスローされた行とともに、可変メッセージで例外をスローできます。

このプログラムはカスタム クラスとマクロを使用して、std::runtime_error を使用して変数メッセージを説明文字列に出力します。

パッケージのインポート

このプログラムには、次の 4つのインポート パッケージが必要です。

#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>

公開クラス

このプログラムはコンストラクター クラスを使用して変数メッセージで例外をスローし、パブリック コンストラクターが std::runtime_error を使用して呼び出されたときにそのカスタム メッセージを説明文字列として表示します。

コード スニペットの最初の行は、クラス my_exception と新しい runtime_error オブジェクトを作成します。 それに伴い、説明変数 string を渡すために使用されるグローバルスコープの文字列オブジェクト msg が作成されます。

コンストラクタークラス my_exception は 3つのパラメーターで初期化されます: 説明文字列を渡す std 文字列オブジェクト arg、ファイルの名前を格納するデータ型 char のポインターオブジェクト *file、および整数変数です。 例外がスローされた行を格納する行。

このオブジェクトが呼び出されたときに出力を表示するために、std::ostringstream で文字列出力オブジェクトが作成されます。 最後に、このオブジェクトは変数 msg に格納されます。

デストラクタ ~my_exception() は、return msg.c_str(); を使用して変数 msg を null で終わる文字列として返します。

class my_exception : public std::runtime_error {
  std::string msg;

 public:
  my_exception(const std::string &arg, const char *file, int line)
      : std::runtime_error(arg) {
    std::ostringstream o;
    o << file << ":" << line << ": " << arg;
    msg = o.str();
  }
  ~my_exception() throw() {}
  const char *what() const throw() { return msg.c_str(); }
};

マクロと例外のスロー

ここでは、#define throw_line(arg) を使用してマクロを定義しています。 throw_line() を呼び出すと、my_exception(arg, __FILE__, __LINE__) がスローされます。

メソッド void f() は、マクロ throw_line を呼び出し、メッセージ Oh no! を渡します。

#define throw_line(arg) throw my_exception(arg, __FILE__, __LINE__);

void f() { throw_line("Oh no!"); }

主な方法

main メソッドは、try ブロック内でメソッド f() を呼び出すことにより、可変メッセージで例外をスローします。 これにより、メッセージ ブロックがメソッド my_exception に渡されます。

catch ブロック内で runtime_error オブジェクト ex が作成され、ex.what() を使用して説明文字列を呼び出します。

説明文字列が呼び出されると、ostream オブジェクトが my_exception コンストラクター内で呼び出され、変数メッセージと共にファイル名とエラー行が返されます。

int main() {
  try {
    f();
  } catch (const std::runtime_error &ex) {
    std::cout << ex.what() << std::endl;
  }
}

完全なコード:

#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>

class my_exception : public std::runtime_error {
  std::string msg;

 public:
  my_exception(const std::string &arg, const char *file, int line)
      : std::runtime_error(arg) {
    std::ostringstream o;
    o << file << ":" << line << ": " << arg;
    msg = o.str();
  }
  ~my_exception() throw() {}
  const char *what() const throw() { return msg.c_str(); }
};
#define throw_line(arg) throw my_exception(arg, __FILE__, __LINE__);

void f() { throw_line("Oh no!"); }

int main() {
  try {
    f();
  } catch (const std::runtime_error &ex) {
    std::cout << ex.what() << std::endl;
  }
}

出力:

D:\c++\std-exceptions\8.cpp:23: Oh no!

--------------------------------
Process exited after 0.006875 seconds with return value 0
Press any key to continue . . .

まとめ

この記事では、変数メッセージを使用して例外をスローし、例外がスローされたときにメッセージを表示するさまざまな方法について説明します。

この記事が、可変メッセージを使用して例外をスローする方法を学習するのに役立ち、実際のシナリオでそれを使用できるようになることを願っています。

関連記事 - C++ Exception