ikautak.log

C/C++, Python, CUDA, Android, Linux kernel, Network, etc.

More Effective C++ 項目14 例外仕様を賢く用いる

新訂版 More Effective C++ (AddisonーWesley professional co)

新訂版 More Effective C++ (AddisonーWesley professional co)

  • 作者: スコット・メイヤーズ,安村通晃,伊賀聡一郎,飯田朱美,永田周一
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 2007/06/29
  • メディア: 単行本(ソフトカバー)
  • 購入: 8人 クリック: 129回
  • この商品を含むブログ (43件) を見る

項目14 例外仕様を賢く用いる

関数が例外仕様にない例外を発生させたとき、特別な関数unexpectedが自動的に起動される。
unexpectedの省略時の振る舞いはterminateを呼ぶことで、terminateの省略時の振る舞いはabortである。
abortは後片付けを行わずにプログラムを停止するので、例外仕様の違反は起こしてならない。

例外仕様を含まない関数f1を考える。

extern void f1();  // 何でも投げる

関数f2はint型例外が発生しうることを宣言。

void f2() throw(int);

次のように書いてもC++としては正しい。

void f2() throw(int) {
  ...
  f1();  // f1はint以外の例外を投げるかも
  ...
}

コンパイラは文句を言わないが、例外が発生するとプログラムが停止するため、こういった例外仕様の矛盾を最小限にする必要がある。


テンプレートと例外仕様は混ぜない

template<class T>
bool operator==(const T& a, const T& b) throw() {
  return &a == &b;
}

このテンプレートは、全ての型にoperator==を定義し、アドレスを比較している。
このテンプレートから生成される関数は例外を発生しないという例外仕様だが、operator&は型によってはオーバーロード可能であり、例外を発生させる可能性がある。
テンプレートの型引数からは例外が発生するかどうかはわからないため、型引数をとるテンプレートに例外仕様をつけてはいけない。


例外仕様を持たない関数を呼ぶ関数には、例外仕様をつけない

例外仕様つきの関数ポインタをtypedefする話だったが、typedefには例外仕様を含めないと標準委員会が宣言したらしく、本に載っている方法は使えないようだ。
省略する。


システムが発生させる例外を扱う

例外仕様を厳密に扱ったソフトを書いているとき、例外仕様を使っていないライブラリを使うとき、予期せぬ例外を予防するためには別の型の例外に変換する。

class UnexpectedException();  // 全ての予期しない例外をこれに置き換える

void convertUnexpected() {  // 予期しない例外が発生したとき呼ばれる関数
  throw UnexpectedException();
}

省略時のunexpected関数を置き換える。

set_unexpected(convertUnexpected);

これで予期せぬ例外は型UnexpectedExceptionの例外になる。

また、unexpected関数の代替関数が現在の例外を発生させなおすと、bad_exceptionになる。

void convertUnexpected() {  // 予期しない例外が発生すると現在の例外を投げる
  throw;
}

set unexpected(convertUnexpected);  // unexpectedの代わりにconvertUnexpectedを使う

これで予期せぬ例外にであっても、bad_exceptionに置き換えられ、プログラムが停止することを防げる。