
A 回答 (12件中1~10件)
- 最新から表示
- 回答順に表示
No.12
- 回答日時:
> たしかに、臭いものに蓋的な考え方ですが、関数やLibraryから例外を投げられることもあるので、その場合はcatchして適切な処理を与えましょう。
みたいな意味合いで書きました。いや、デストラクタでは、そもそも例外が送出されるかもしれない関数を呼び出すこと自体を避けるべきです。
例えば何かを外部に出力する場合でも、std::ofstreamよりは、決して例外を送出しないstd::fprintfなどを使う方がよいということです。
> コンストラクタは例外を投げない方が良い。
コンストラクタ内で発生したエラーの通知は、例外を送出することで行うべきです。もっと分かりやすくいうと、コンストラクタが失敗した場合は例外を送出した方がよいのです。
> デストラクタは例外を投げてはいけない。
これはその通り。
> メソッドは例外を投げない方が無難。
(メソッドというか)メンバ関数は必要に応じて例外を送出してかまいません。
No.11
- 回答日時:
御意>#10さん
> このようなこともあり、例えばSTL等では例外を投げないことを要求されたりもします。
先にも少し書いたつもりでしたが、STL等は「渡すデータのデストラクタが例外を投げない」ことを "要求" します。
つまり、例外を投げるデータをSTLに渡してはいけない(契約違反)ということです。
それ以外の場合でも、デストラクタからは例外を投げない設計が無難。
理由は既出ですが、タスク例外とかは本当に環境依存の最終手段でしょうし、一般的には投げていい場合の方がかなり限られます。
No.10
- 回答日時:
以下の2点に関して、もしかすると誤解されている可能性があるので、念のため再確認します。
> 3.デストラクタでの例外でも内部でcatchすれば問題ない。
デストラクタ内部で例外をcatchしても、それだけでは臭いものに蓋をしただけで解決にはなりません。
原則として、デストラクタでは例外を送出しないようにしましょう。
> 4.STLを使用するなら例外を投げない方が無難。
STLというか、標準C++ライブラリや、多くのまともなライブラリは、ユーザー定義クラスのデストラクタから例外が送出されないことを前提にしています。
例外を投げない方が無難なのではなく、「デストラクタから」例外を送出してはいけないということです。
回答ありがとうございます。
>> 3.デストラクタでの例外でも内部でcatchすれば問題ない。
たしかに、臭いものに蓋的な考え方ですが、関数やLibraryから例外を投げられることもあるので、その場合はcatchして適切な処理を与えましょう。みたいな意味合いで書きました。
>> 4.STLを使用するなら例外を投げない方が無難。
コンストラクタは例外を投げない方が良い。
デストラクタは例外を投げてはいけない。
メソッドは例外を投げない方が無難。
ということですか?
No.9
- 回答日時:
デストラクタで止めた例外の行き場に関しては、ひとつだけ裏技的な解法があります。
それは、異なるタスクに例外を通知し、そこで例外を処理させる方法です。もちろん、ここでいう例外の通知方法も処理方法も、C++が言語レベルでサポートする監視ブロックとは異なるものです。
もっとも、そこまでやるのはよほどの状況ですし、ほぼすべての場合でデストラクタからの例外送出は禁止すべきですね。デストラクタからの例外送出は、gotoの1万倍は凶悪です。
最初の質問に戻ると、デストラクタからの例外とは違って、(馬鹿なコンパイラさえ使わなければ)コンストラクタからの例外送出は至って健全です。
回答ありがとうございます。
ここまでの意見を見ますと、
1.コンストラクタでの例外はリークやデータの破損に気をつけて使用できる。
2.デストラクタでの例外をオブジェクトの外側に投げることはC++言語の設計上ほとんど不可能。
3.デストラクタでの例外でも内部でcatchすれば問題ない。
4.STLを使用するなら例外を投げない方が無難。
と、言うことですね。
No.8
- 回答日時:
御意>#7さん
設計上、そもそも投げない仕様か、投げても安全と保証できる用法なら問題はないです。
このような保証が得られない場合に、
uncaught_exception()が入っている方がterminateハンドラよりはマシなんじゃないかと個人的には思いますが、
結局のところは、ここで止めた例外の行き場が問題になる可能性があります。
例えば、例外中に例外が発生するケースだと、
最初の例外に起因しただけで最初の例外さえ正しく処理すれば後の例外は安全に無視できる、などという場合もありえますが、
後の例外が無条件に例外を投げるとterminateのグローバルハンドラで判断するしかなくなってしまいますので、uncaught_exceptionは有効だと思います。
# コンパイラが"正しく"対応していれば。
そうでないような場合(例外は投げるが呼び出し条件の保証もなく、例外中に例外が発生すると不正)が多いことも考えると、
一般則としては「デストラクタで例外を投げてはいけません」に落ち着くと思ってます。
No.7
- 回答日時:
デストラクタでの例外についてもついでにコメントしておくと...
ごくごく限られた状況でしか使用しない(というか使用状況を強制するように設計された)クラスであれば、デストラクタから例外を送出しても問題ないとは思います。
具体的には、関数内で定義されたローカルクラスで、二重例外やコンテナの要素になる可能性を完全に排除できている場合などです。
ちなみに、デストラクタから例外を送出してはいけないからといって、単に例外をcatchして捨てるだけの行為は凶悪ですのでやめましょう。
No.6
- 回答日時:
> このような処理は、コンストラクタに入れて大丈夫なのでしょうか?
コンストラクタ内での例外の場合でも、通常の関数内処理は
> // 例外で影響を受けるものの修復等
この部分がキチンとなっていれば大丈夫です。
デストラクタが無い前提で、その時点までの状態をロールバックする。(面倒ですが…。既に指摘があるようにauto_ptrとかは役に立ちます)
コンストラクタで特に注意が必要なのは初期化指定で、#3の方が書かれているようなtry blockが必要です。
# これに対応してないコンパイラとかもまだ出回ってます。
ちなみに、初期化処理の場合、
: p1(new B), p2(new C)
と書いてあっても、この順番に初期化されるわけではないとか(記述順ではなく、クラスでの定義順に依存する)、はまりどころも満載です。
*** *** ***
> また、このように例外が発生することを前提とするコードでも
> デストラクタには入れられないのでしょうか?
デストラクタ内部で例外が出るのは大丈夫ですが、外に投げたらいけません。
ここでいう「いけません」は、言語レベルでの禁止ではありません。
やることは可能ですが、例えば以下のような危険をはらみます。
例外処理中に例外がおきるとterminateされてしまうので、例外発生時のロールバック中にデストラクタが例外を出すと、プログラムが死にます(terminateのデフォルト処理はabort)。
そして、catchもできません。
なので、とりあえず、
> throw; // これで関数外まで例外を飛ばす
これは、uncaught_exceptionで判定してから再投入を決めるか、そもそも「投げない方が無難」です。
# uncaught_exceptionも同様に、まともに動かないコンパイラがまだ出てます。
このようなこともあり、例えばSTL等では例外を投げないことを要求されたりもします。
No.5
- 回答日時:
> コンストラクタが例外を投げても問題ないということですか?
御意。既に回答があるように、それが本来の正しい(?)用法です。
ただし、例外に対する正しい理解をもつ開発者は少ないです。
C言語にはこのような例外がありませんでしたので、
例えば手探りで移行した人で知識が抜けていたりとか、
C++の入門書でも説明が少なくて知らない人が増えたりとか、
bad_allocすら投げない、try blockも使えない、
でも有名な某コンパイラが幅を利かせたりとかもありますし、
Cでは安全だったコードがC++では例外脆弱だったりとか、
違う言語なので当たり前なのですが認識の無い人も多かったりするのが現実。
Java/C#等の類似言語も、そもそもデストラクタが無かったりして
C++の例外に対する誤った認識を与えてしまうことが多々あります。
# 「尖がったC++」と比べて少し丸い言語たちですから、
# これらの言語自体はそれでいいのですが、C++で同じ感覚だとは問題が…。
コンストラクタに限らず、例外を投げただけで呼びもとの処理が例外脆弱だと問題を起こす可能性があり、このことについてもある程度の配慮は必要であるとは思います。
なお、デストラクタでは例外を発生させてはいけません。
例外安全性が保てなくなります。
曖昧な記憶とのことですので、これと混同されている可能性はあるかと思います。
回答ありがとうございます。
私は、たとえばnewで言うなら
try{
new char[0x7fffffff]; // ここで例外が発生
}
catch(std::bad_alloc val){
// 例外で影響を受けるものの修復等
throw; // これで関数外まで例外を飛ばす
}
というような処理をよくやります。
このような処理は、コンストラクタに入れて大丈夫なのでしょうか?
また、このように例外が発生することを前提とするコードでもデストラクタには入れられないのでしょうか?
No.4
- 回答日時:
> デストラクタが動かないことを前提にリークに気をつければ、コンストラクタが例外を投げても問題ないということですか?
実際にはリークだけの話ではありません。
引数としてポインタや参照が渡された場合、途中で例外が発生しても、それらの内容を(できれば)破壊すべきではありませんし、静的データメンバ等の状態を変化にも注意しないと、その後の整合性が保てなくなります。
No.3
- 回答日時:
コンストラクタで例外を発生させてはいけないというのは嘘です。
そもそも、オブジェクトの生成に失敗したことを通知するには、返却値のないコンストラクタの場合は例外を送出する以外にありません(errnoのような方法もあるにはありますが...)。コンストラクタでの例外発生にまつわる問題を回避する最も簡単な方法は、new演算子(または似たような方法でのリソース確保)を複数行わないようにすることです。
A::A()
try
: p1(new B), p2(new C)
{
}
catch (std::bad_alloc& e)
{
}
のようにしても、例外はcatchできますが、果たしてp1で例外が発生したのか、p2で例外が発生したのか知るすべがありません。
これだけの問題であれば、auto_ptrを使えば逃げられますが、例外安全に対して理解の浅いプログラマの場合は、ついつい信頼性の低いコードを書いてしまいがちです。
誤解のないように念を押しますが、コンストラクタの内部で発生したエラーの通知には例外を使用すべきです。しかし、同時に例外安全に対する認識と、具体的な対応方法を身に付けることが必須です。
回答ありがとうございます。
つまり、デストラクタが動かないことを前提にリークに気をつければ、コンストラクタが例外を投げても問題ないということですか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- 日本語 「~でも」(~で)「~さえ」の細かい違い その2 2 2023/08/20 17:20
- SSL・HTTPS 知恵袋ページの私的な不具合について 7 2023/01/07 18:46
- その他(悩み相談・人生相談) テイカーのメリットは何ですか? 1 2023/06/13 13:16
- 法学 労働紛争の口外禁止条項とはどこまでの制限がありますか? 2 2022/10/15 22:48
- 食べ物・食材 大阪湾の天然カキ 貝毒を避けて食べられる? 2 2022/09/25 23:53
- 日本語 読解力の質問です(Excel含む) 12 2022/08/02 13:25
- その他(自然科学) 直流モータのω-τ曲線につきまして 1 2022/09/10 18:46
- 日本語 "が" と "は" について。 ある質問へのある回答を読んでいて、かなり違和感を覚えました。 htt 1 2023/05/02 18:24
- 事件・犯罪 日本での話ですが、自分が着てる服の意味知らないで、デザイン好きだからって着てたらトラブルになるって事 2 2022/04/30 12:27
- 哲学 世界に例外のないものはない。 3 2022/11/01 02:18
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
「タイプ初期化子が例外をスロ...
-
Javaの例外 IllegalArgumentExc...
-
VBA Evaluate関数 型が一致しま...
-
Timestamp型への変換について(J...
-
全角スペースのチェックについて
-
0除算の例外処理ができない!!...
-
C#の捕捉されない例外処理の対...
-
Javaで文字列をゼロ埋め(ゼロパ...
-
VBA 400エラー 1004エラー
-
Excelでのエラー
-
C# UriFormatExceptionの回避
-
VB.Net Object型 空かどうか
-
java 文字列の部分一致について
-
時間の取得
-
連続する「\\」をひとつの「\\...
-
例外ってIf文の中に入れますか...
-
初回例外
-
エクセルVBAで、条件に一致する...
-
VBA コピーが出来ません…!
-
private static という変数の修飾
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
「タイプ初期化子が例外をスロ...
-
C#の捕捉されない例外処理の対...
-
VB.Net Object型 空かどうか
-
連続する「\\」をひとつの「\\...
-
VC++におけるCStringの変換
-
VBA Evaluate関数 型が一致しま...
-
Javaで文字列をゼロ埋め(ゼロパ...
-
ファイルダイアログを開いた時...
-
VB.NETで16進数が正しいかどう...
-
Timestamp型への変換について(J...
-
C# マルチスレッドにおける例外...
-
コンストラクタでの例外は不可...
-
文字列からダブルクオートの削除
-
String型の日付(2005/11/25)の...
-
例外ってIf文の中に入れますか...
-
初回例外
-
【JAVA】与えられた金額を貨幣...
-
アサーションと例外処理の違い...
-
VBA 400エラー 1004エラー
-
WebClient()以外でネットにアク...
おすすめ情報