[C++] 例外処理のメモ

例外処理に利用するクラスなどはヘッダをインクルードして使う。C++11 で追加された例外はどう使えばいいのかよくわからないけど、たぶん私のようなバカには無用のものだろうと思うのでまぁどうでもいいか…


std::runtime_error 例外処理

C++の標準の例外は全てstd::excpeption の派生クラス(stdexceptヘッダ参照)になっている。

参考 : C++編(標準ライブラリ) 第27章 例外クラス

C++は例外としてどんな型でも投げられる(voidは無理)けども
std::exception の派生クラスを普通は作る。

C++の例外はスタックトレースとか取れない。

またデストラクタから例外を送出してはならない。

void thrower(bool b) throw(int)
{
  if (b)
  {
    throw 100;
  }
  else
  {
    throw "not int";
  }
}

int main()
{
  try
  {
    throw std::runtime_error("TEST");
  } catch (std::runtime_error e) {
    puts(e.what()); // TEST
  }

  try
  {
    throw nullptr;
  }
  catch (...) // どんな型でも受け取れる
  {
    puts("nullptr");
  }

  try
  {
    thrower(true);
  }
  catch (const char *text)
  {
    puts(text); // ここは通らない
  }
  catch (int &i)
  {
    printf("%d\n", i); // 100
  }

  try
  {
    thrower(false); // terminate called throwing an exception
  }
  catch (...)
  {
    puts("ココを通らずにプログラム実行終了");
  }
}

例外仕様の記述が無い場合にキャッチしないと関数外に送出されずに実行終了する。
ただし std::runtime_error は例外仕様を記述する必要がないっぽい。

noexcept (C++11)

noexcept は例外仕様で throw() と書いた場合と同じ効果。
noexcept(true) とすると例外を投げうるが、例外の指定はできない。
C++11でthrowによる例外仕様は非推奨となり、代わりにnoexpectを使う。

exception_ptr (C++11)

exception_ptrはあらゆる例外を保持できる。
current_exceptionは現在のcatchブロック内の例外を取得できる。
rethrow_exceptionはexception_ptrを再スローする。
make_exception_ptrでexception_ptrを生成できる

std::exception_ptr ep;

try
{
  throw 123;
}
catch (...)
{
  // int型などの例外でも current_exception で取得できる
  ep = std::current_exception();
}

try
{
  std::rethrow_exception(ep); // もっかい投げられる
}
catch (int e)
{
  std::cout << e << std::endl;
}

// exception_ptr 自体を作る場合は make_exception_ptr
std::runtime_error e("TEST");
ep = std::make_exception_ptr(e);

try
{
  std::rethrow_exception(ep);
}
catch (std::runtime_error e)
{
  std::cout << e.what() << std::endl;
}

nested_exception (C++11)

nested_exceptionは名前通り入れ子の例外であり多重継承のmixinとして利用する。

//
// nested_exceptionは
//
class E : public std::nested_exception {
 public:
  int tag;
  E(int tag) : tag(tag) {};
};

try
{
  throw "TEST";
}
catch (...)
{
  try
  {
    throw E(1);
  }
  catch (E e)
  {
    std::cout << e.tag << std::endl; // 1

    try
    {
      // 内包された例外を送出
      e.rethrow_nested();
    }
    catch (const char * text)
    {
      std::cout << text << std::endl; // TEST
    }

    try
    {
      // .nested_ptr() で内包された例外を取得可能
      std::exception_ptr ep = e.nested_ptr();
      std::rethrow_exception(ep);
    }
    catch (const char *text)
    {
      std::cout << text << std::endl; // TEST
    }
  }
}

//
// catchブロック外で生成してもネストした例外は空
//
try
{
  throw E(2);
}
catch (E e)
{
  if ( ! e.nested_ptr())
  {
    std::cout << "no nested ptr" << std::endl;
  }
}

//
// rethrow_if_nested は
//   nested_ptr であれば中身(ネストされた例外)を送出する
//   ネストした例外が無いとダメ
//
try
{
  std::string foo = "foo";
  std::rethrow_if_nested(foo); // 何もおこらない
  throw foo;
}
catch (std::string &foo)
{
  //
  // throw_with_nested は
  //   引数が nested_ptr であればそのまま送出し
  //   引数が nested_ptr でなければ nested_ptrと引数の型を継承した派生クラスを送出する
  //     なので継承できないクラスは throw_with_nested に渡せない
  //
  try
  {
    // ここで投げられる例外は nested_ptr でも runtime_error でも catch できる
    // foo をネストした例外が投げられる
    std::throw_with_nested(std::runtime_error("bar"));
  }
  catch (std::runtime_error &bar)
  {
    std::cout << bar.what() << std::endl; // bar
    try
    {
      std::rethrow_if_nested(bar);
    }
    catch (std::string &foo)
    {
      std::cout << foo << std::endl; // foo
    }
  }
}
    • うなぎ
    • 2015年 2月3日

    もの凄く初心者の質問なのですが、
    void thrower(bool b) throw(int)
    この throw(int)の部分は、どういう意味なのでしょうか?
    C言語は少しわかるのですがC++の文法は良く分りません。
    こんな関数の書き方はC言語では見た事がないので、ググル上で
    キーワードなど教えて下さい。

  1. > うなぎさん
    「例外仕様」とか「例外指定」とかいうキーワードで検索すると出てきます。
    ※C++11 ではこの記述は非推奨になり、代わりにnoexceptを使います。

    • うなぎ
    • 2015年 2月4日

    さっそくググッてみます。
    ありがとございました。

  1. トラックバックはまだありません。

*


Advertisement