web-dev-qa-db-ja.com

新しいstd :: exceptionを投げるvs std :: exceptionを投げる

偶然見つけたコードを見ながら:

throw /*-->*/new std::exception ("//...

ここでnewを使用する必要はない/使用すべきでないといつも思っていました。
正しい方法は何ですか、両方とも大丈夫ですが、そうであれば違いはありますか?

ところで、PowerShell Boostライブラリで「グレッピング」しているときに見ることができるものから、throw newを使用することはありません。

追伸また、throw gcnewを使用するCLIコードを見つけました。それは大丈夫ですか?

102
NoSenseEtAl

例外をスローおよびキャッチする従来の方法は、例外オブジェクトをスローし、参照(通常はconst参照)によってキャッチすることです。 C++言語では、コンパイラが適切なコードを生成して例外オブジェクトを構築し、適切なタイミングで適切にクリーンアップする必要があります。

動的に割り当てられたオブジェクトへのポインタを投げることは、決して良い考えではありません。例外を使用すると、エラー状態に直面しても、より堅牢なコードを作成できます。従来の方法で例外オブジェクトをスローすると、catch (...)によって正しい型を指定するcatch句でキャッチされるかどうか、その後再スローされるかどうかを確認できます。適切なタイミングで正しく破壊されました。 (唯一の例外は、まったくキャッチされない場合ですが、これはあなたがどのように見ても回復不可能な状況です。)

動的に割り当てられたオブジェクトへのポインターをスローする場合、例外をスローしたい時点で呼び出しスタックがどのようなものであっても、正しいポインター型を指定し、適切なdelete呼び出し。そのブロックが例外を再スローしない限り、catch (...)で例外をキャッチしてはなりません。例外は、例外を正しく処理する別のcatchブロックでキャッチされます。

事実上、これは、堅牢なコードを記述しやすくし、すべての状況で正しいコードを記述するのを非常に困難にする例外処理機能を採用したことを意味します。これにより、この機能を想定していないクライアントコードのライブラリコードとして機能することはほとんど不可能になるという問題がなくなります。

81
CB Bailey

例外をスローするときにnewを使用する必要はありません。

書くだけ:

throw yourexception(yourmessage);

としてキャッチ:

catch(yourexception const & e)
{
      //your code (probably logging related code)
}

yourexceptionstd::exceptionから直接または間接的に派生することに注意してください。

28
Nawaz

呼び出しサイトがnew std::exceptionをキャッチすることを期待している場合、std::exception*を投げることは正しいです。しかし、例外へのポインタをキャッチすることを期待する人はいません。それがあなたの関数が行うことを文書化し、人々が文書を読んだとしても、彼らはまだ忘れて、代わりにstd::exceptionオブジェクトへの参照をキャッチしようとする傾向があります。

22
Hurkyl

C++ FAQでこれに関する素晴らしい議論があります:

  1. https://isocpp.org/wiki/faq/exceptions#what-to-catch
  2. https://isocpp.org/wiki/faq/exceptions#catch-by-ptr-in-mfc

基本的に「参照しないでキャッチする正当な理由がない限り、参照によるキャッチ。値によるキャッチは避けてください。コピーが行われ、コピーはスローされたものと異なる動作をする可能性があります。 」

7
user1202136