[解決済み] C++で例外指定子を使うべきですか?
2022-07-15 16:43:34
質問
C++では、例外指定子を使って、関数が例外を投げるか否かを指定することができます。例えば
void foo() throw(); // guaranteed not to throw an exception
void bar() throw(int); // may throw an exception of type int
void baz() throw(...); // may throw an exception of some unspecified type
などがあり、実際に使うには疑問が残ります。
- コンパイラは厳密な方法で例外指定子を強制しないので、メリットはあまりない。理想を言えば、コンパイル エラーを出すことです。
- 関数が例外指定子に違反した場合、標準的な動作はプログラムを終了させることだと思います。
- VS.Netではthrow(X)をthrow(...)として扱うので、標準への固執が強くない。
例外指定子は使うべきと思いますか?
yes"またはno"で答え、あなたの答えを正当化する理由をいくつか提示してください。
どのように解決するのですか?
いいえ。
その理由をいくつかの例で紹介します。
-
テンプレートコードは例外指定で書けなくなる。
template<class T> void f( T k ) { T x( k ); x.x(); }
コピーは投げるかもしれないし、パラメータ渡しは投げるかもしれない、そして
x()
は何らかの未知の例外を投げるかもしれません。 -
例外仕様は、拡張性を禁止する傾向があります。
virtual void open() throw( FileNotFound );
に進化する可能性があります。
virtual void open() throw( FileNotFound, SocketNotReady, InterprocessObjectNotImplemented, HardwareUnresponsive );
という書き方もできます。
throw( ... )
1番目は拡張性がなく、2番目は大げさで、3番目は仮想関数を書くときに本当に意味することです。
-
レガシーコード
他のライブラリに依存するコードを書くとき、何かがひどくうまくいかなかったときに、そのライブラリが何をするのか本当に知りません。
int lib_f(); void g() throw( k_too_small_exception ) { int k = lib_f(); if( k < 0 ) throw k_too_small_exception(); }
g
が終了するのはlib_f()
を投げます。これは(ほとんどの場合)本当に必要なものではありません。std::terminate()
は決して呼ばれるべきではありません。処理されない例外でアプリケーションをクラッシュさせる方が、黙って/暴力的に死ぬよりも、スタックトレースを取得することができるので、常に良いことです。 -
一般的なエラーを返し、例外的な場面で投げるようなコードを書きましょう。
Error e = open( "bla.txt" ); if( e == FileNotFound ) MessageUser( "File bla.txt not found" ); if( e == AccessDenied ) MessageUser( "Failed to open bla.txt, because we don't have read rights ..." ); if( e != Success ) MessageUser( "Failed due to some other error, error code = " + itoa( e ) ); try { std::vector<TObj> k( 1000 ); // ... } catch( const bad_alloc& b ) { MessageUser( "out of memory, exiting process" ); throw; }
とはいえ、ライブラリが独自の例外を投げるだけの場合、例外指定を使って意図を示すことができます。
関連
-
[解決済み] static_cast, dynamic_cast, const_cast, reinterpret_cast はいつ使うべきですか?
-
[解決済み] Pythonで例外を手動で発生(スロー)させる
-
[解決済み] JUnit 4のテストで、ある例外が投げられたことをどのように断言しますか?
-
[解決済み] スマートポインターとは何ですか?
-
[解決済み] なぜ、オブジェクトそのものではなく、ポインタを使用しなければならないのですか?
-
[解決済み] 仮想デストラクタはいつ使うのか?
-
[解決済み] C++でクラスと構造体はいつ使い分けるべきか?
-
[解決済み] Pythonで例外を表示するには?
-
[解決済み] noexceptを本当に使うべきはいつですか?
-
[解決済み】なぜC++プログラマは'new'の使用を最小限に抑えなければならないのでしょうか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】C++ クラスヘッダが含まれているときに「不明な型」があるのはなぜですか?重複
-
[解決済み】LLVMで暗黙のうちに削除されたコピーコンストラクタの呼び出し
-
[解決済み】C++コンパイルタイムエラー:数値定数の前に期待される識別子
-
[解決済み】C++エラーです。"配列は中括弧で囲まれたイニシャライザーで初期化する必要がある"
-
[解決済み】Cygwin Make bash コマンドが見つかりません。
-
[解決済み】エラー:strcpyがこのスコープで宣言されていない
-
[解決済み】エラー。switchステートメントでcaseラベルにジャンプする
-
[解決済み] noexceptを本当に使うべきはいつですか?
-
[解決済み] 現在のCまたはC++の標準文書はどこにありますか?
-
[解決済み】関数のシグネチャでthrowキーワードを使用する場合