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


113

私が偶然見つけたいくつかのコードを見ている間:

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

そして、私はあなたが必要としない/あなたがnewここで使うべきではないといつも思っていました。
正しい方法は何ですか、どちらも問題ありませんが、違いはありますか?

ところで、PowerShellブーストライブラリで「把握」しているときに私が見ることができるものからは、決して使用しませんthrow new

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


1
throw gcnew役に立つと思います。マネージコードで例外をキャッチする場合。誰かがそれについて私を訂正できますか?
jpalecek

1
.Netは例外をポインターで処理するので、そこでgcnewをスローするのが適切です。
Sebastian Redl

1
@SebastianRedl .Net "ポインタ"があいまいかもしれませんか?gcnewは確かにそうではありませんが。 System::Exception通常は、ガベージコレクションされたヒープ上の管理対象オブジェクトへの参照です。私はいつもと一緒に投げられgcnew、つかまえてきましたSystem::Exception ^。もちろんfinally、C ++ / CLIでも常に使用していますが、同じtryブロックでC ++の例外と混同することはあまりありませんが、理由はわかりません。

回答:


89

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

動的に割り当てられたオブジェクトへのポインタを投げることは決して良い考えではありません。例外は、エラー条件が発生した場合に、より堅牢なコードを記述できるようにするためのものです。通常の方法で例外オブジェクトをスローする場合、正しいタイプを指定するcatch節によってキャッチされるcatch (...)かどうか、それが再度スローされるかどうかに関係なく、適切なときに正しく破棄されます。(唯一の例外は、まったく検出されない場合ですが、これはどのように見ても回復不可能な状況です。)

動的に割り当てられたオブジェクトへのポインターをスローする場合は、例外をスローしたい時点でコールスタックがどのように見えるかにかかわらず、正しいポインタータイプを指定し、適切なdelete呼び出しを行うcatchブロックがあることを確認する必要があります。catch (...)そのブロックが例外を再スローしない限り、例外はキャッチされないはずです。例外は、例外を正しく処理する別のキャッチブロックによってキャッチされます。

事実上、これは、堅牢なコードの記述を容易にし、あらゆる状況で正しいコードの記述を非常に困難にする例外処理機能を使用したことを意味します。これは、この機能を期待しないクライアントコードのライブラリコードとして機能することがほぼ不可能になるという問題を残しています。


1
「例外オブジェクトを投げる」スタックまたは私の友人を積み上げますか?スタックまたはヒープ?(多分私はどこかで悪いグローバルな例を見ていました)ああ、そしてスタックの場合、適切なスコープは何ですか?

@ebyrob:あなたが何を求めているのか本当にわかりませんが、ここで答えられるかもしれない例外オブジェクトのストレージや寿命について知りたいようです。そうでない場合は、別の質問をすることをお勧めします。
CBベイリー

31

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

書くだけ:

throw yourexception(yourmessage);

としてキャッチ:

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

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


7
どうして?なぜ使用しないのnewですか?なぜ由来yourexceptionするのstd::exceptionですか?
Walter

私が怠惰なとき(これはよくあることですが)なぜ動作しないのthrow std::exception;ですか?g ++はコンパイルしないようです...

7
@ebyrob:std::exceptionは型であり、型をスローすることはできません。オブジェクトをスローする必要があります。したがって、構文は次のようになります:throw std::exception();コンパイルされます。それがどれほど優れているかは、まったく別の質問です。
Nawaz 2013

22

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


27
new std::exception呼び出しサイトがポインターをキャッチすることを期待していて、割り当て例外の管理を引き継ぐことを期待していて、明示的にキャッチしないものによって関数が呼び出されることは決してない場合、スローは正しい正しいポインタ(catch(...)またはまったく処理しない)の場合、オブジェクトリークが発生します。要するに、これは「絶対に」と近似することができます。
CBベイリー

正解が@CharlesBaileyのコメントである場合、この回答がどのように受け入れられたのかは不思議です。
John Dibling 2012年

@ジョン:それも私の心を越えました。しかし、ワンツーパンチは私にドライサマリーを提供することで良い影響を与えると思います。チャールズは人々がそれを適切に処理することを忘れがちなさまざまな方法を面白く拡大しています。残念ながら、投票されたコメントから評判を得ることができません。

チャールズは彼の答えを提供しませんでした、そしてこのAは(他のものとは異なり)Aとコメントの両方に説明があります。
NoSenseEtAl

9

C ++ FAQはこれについて素晴らしい議論があります:

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

基本的には、「しないでください。正当な理由がない限り、参照でキャッチします。値によるキャッチは避けてください。コピーが作成され、コピーはスローされたものとは異なる動作をする可能性があります。非常に特殊な状況でのみ、ポインタでキャッチする必要があります。 」


2
いつものように、FAQは不適切な言葉で書かれています。値または参照でキャッチできます。ポインタはたまたま値です(値または参照でキャッチします)。タイプAはタイプとは異なるA*ので、完全に異なるタイプであるthrow A()ため、キャッチできない場合がありますcatch(A* e)
マーティンヨーク

これらのリンクは現在壊れています。
stephenspann

1
@spanndemicのリンクを修正しました
user1202136

1

オペレーターnewは、例外が発生しないことを保証できません。このため、「有効な」(意図された)例外をスローするためにそれを使用すると、クラッシュしないことを保証できないコードが生成されます。一度に1つだけ例外があり、プログラムがそれらをキャッチする前に2つをスローしようとするため、実装ができる最善のことは、たとえばstd :: terminateを呼び出すことによって、プログラムをただちに中止することです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.