(本当に)例外安全なコードを書いていますか?[閉まっている]


312

例外処理(EH)は現在の標準のようで、Webを検索しても、それを改善または置換しようとする新しいアイデアや方法は見つかりません(まあ、いくつかのバリエーションは存在しますが、新しいものはありません)。

ほとんどの人はそれを無視するか受け入れるだけのようですが、EHにいくつかの大きな欠点があります。例外はコードからは見えず、非常に多くの可能な出口点を作成します。ソフトウェアのジョエルはそれについて記事を書いた。goto完璧に合うと比較すると、EHについてもう一度考えさせられました。

私はEHを避けて、戻り値、コールバック、または目的に合ったものを使用します。しかし、信頼性の高いコードを記述する必要がある場合、EHを無視することはできません。これは、new(昔のように)単に0を返すのではなく、例外をスローするで始まります。これにより、C ++コードのすべての行が例外に対して脆弱になります。そして、C ++基本コードのより多くの場所が例外をスローします... std libはそれを行います、など。

これは不安定な場所を歩いているような気がします。だから、今、私たちは例外に注意することを余儀なくされています!

しかし、それは難しい、本当に難しい。あなたは例外安全なコードを書くことを学ぶ必要があり、それである程度の経験があっても、安全であるためにはコードの1行を再確認する必要があります!または、try / catchブロックをいたるところに配置し始め、コードが読みにくくなるまでコードが乱雑になります。

EHは、ごく少数の、しかし理解しやすく、簡単に解決できる欠点があった古いクリーンな確定的アプローチ(戻り値..)を、コードに多くの可能な出口点を作成するアプローチに置き換え、例外をキャッチするコード(ある時点で実行することを余儀なくされます)、その後、コードを介して多数のパスを作成します(catchブロックのコード、std :: cerr以外のロギング機能が必要なサーバープログラムについて考えてください。)。EHには利点がありますが、それが目的ではありません。

私の実際の質問:

  • あなたは本当に例外安全なコードを書いていますか?
  • あなたの最後の「プロダクションレディ」コードは例外的に安全ですか?
  • あなたはそれがそうであると確信することさえできますか?
  • 機能する代替案を知っているか、実際に使用していますか?

44
「EHは古いクリーンな決定論的アプローチ(戻り値..)を置き換えました」何ですか?例外は、戻りコードと同じように確定的です。それらについてランダムなものは何もありません。
rlbond 2009

2
EHは(さえエイダ以来!)長い時間のための標準となっている

12
「EH」は例外処理の確立された略語ですか?今まで見たことがありません。
Thomas Padron-McCarthy

3
ニュートンの法則は今日、ほとんどのことに適用されます。彼らが何世紀にもわたって非常に幅広い現象を予測してきたという事実は重要です。
David Thornley、

4
@frunsi:ああ、混乱させてすみません!しかし、どちらかといえば、奇妙で説明のつかない頭字語や略語は、人々を落胆させることになると思います。
Thomas Padron-McCarthy

回答:


520

あなたの質問は、「例外安全なコードを書くことは非常に難しい」という主張をします。私はまずあなたの質問に答え、それから彼らの背後に隠された質問に答えます。

質問に答える

あなたは本当に例外安全なコードを書いていますか?

もちろんするよ。

これが JavaがC ++プログラマとしての魅力の多くを失った理由です(RAIIセマンティクスの欠如)が、余談ですが、これはC ++の質問です。

実際には、STLまたはBoostコードを操作する必要がある場合に必要です。たとえば、C ++スレッド(boost::threadまたはstd::thread)は例外をスローして正常に終了します。

あなたの最後の「プロダクションレディ」コードは例外的に安全ですか?

あなたはそれがそうであると確信することさえできますか?

例外安全なコードを書くことは、バグのないコードを書くことに似ています。

コードが例外的に安全であることを100%保証することはできません。しかし、その後、よく知られているパターンを使用し、よく知られているアンチパターンを避けて、そのために努力します。

機能する代替案を知っているか、実際に使用していますか?

C ++に実行可能な代替手段はありません(つまり、Cに戻し、C ++ライブラリを回避する必要があります。また、Windows SEHのような外部の驚きもありません)。

例外安全なコードを書く

例外安全なコードを書くには、まず、各命令がどのレベルの例外安全かを知る必要があります。

たとえば、a newは例外をスローできますが、組み込み(たとえば、intやポインタ)の割り当ては失敗しません。スワップが失敗することはありません(スロースワップを記述しないでください)std::list::push_back

例外保証

最初に理解する必要があるのは、すべての関数によって提供される例外保証を評価できる必要があるということです。

  1. none:コードはそれを提供するべきではありません。このコードはすべてをリークし、最初にスローされた例外でブレークダウンします。
  2. 基本:これは、最低限提供する必要がある保証です。つまり、例外がスローされても、リソースはリークされず、すべてのオブジェクトがまだ完全です。
  3. strong:処理は成功するか、例外をスローしますが、スローすると、データは処理がまったく開始されなかった場合と同じ状態になります(これにより、C ++にトランザクション機能が提供されます)。
  4. nothrow / nofail:処理は成功します。

コードの例

次のコードは正しいC ++のように見えますが、実際には「なし」の保証を提供しているため、正しくありません。

void doSomething(T & t)
{
   if(std::numeric_limits<int>::max() > t.integer)  // 1.   nothrow/nofail
      t.integer += 1 ;                              // 1'.  nothrow/nofail
   X * x = new X() ;                // 2. basic : can throw with new and X constructor
   t.list.push_back(x) ;            // 3. strong : can throw
   x->doSomethingThatCanThrow() ;   // 4. basic : can throw
}

この種の分析を念頭に置いて、すべてのコードを記述します。

提供される最低の保証は基本ですが、各命令の順序付けにより、関数全体が「なし」になります。これは、3。スローするとxがリークするためです。

最初に行うことは、関数を「基本」にすることです。つまり、リストが安全に所有するまでxをスマートポインタに入れます。

void doSomething(T & t)
{
   if(std::numeric_limits<int>::max() > t.integer)  // 1.   nothrow/nofail
      t.integer += 1 ;                              // 1'.  nothrow/nofail
   std::auto_ptr<X> x(new X()) ;    // 2.  basic : can throw with new and X constructor
   X * px = x.get() ;               // 2'. nothrow/nofail
   t.list.push_back(px) ;           // 3.  strong : can throw
   x.release() ;                    // 3'. nothrow/nofail
   px->doSomethingThatCanThrow() ;  // 4.  basic : can throw
}

現在、私たちのコードは「基本的な」保証を提供しています。何もリークせず、すべてのオブジェクトが正しい状態になります。しかし、より強力な保証を提供することができます。これはコストがかかる可能性がある場所であり、これがすべての C ++コードが強力なわけではない理由です。試してみよう:

void doSomething(T & t)
{
   // we create "x"
   std::auto_ptr<X> x(new X()) ;    // 1. basic : can throw with new and X constructor
   X * px = x.get() ;               // 2. nothrow/nofail
   px->doSomethingThatCanThrow() ;  // 3. basic : can throw

   // we copy the original container to avoid changing it
   T t2(t) ;                        // 4. strong : can throw with T copy-constructor

   // we put "x" in the copied container
   t2.list.push_back(px) ;          // 5. strong : can throw
   x.release() ;                    // 6. nothrow/nofail
   if(std::numeric_limits<int>::max() > t2.integer)  // 7.   nothrow/nofail
      t2.integer += 1 ;                              // 7'.  nothrow/nofail

   // we swap both containers
   t.swap(t2) ;                     // 8. nothrow/nofail
}

操作を並べ替え、最初に作成Xして適切な値に設定しました。いずれかの操作が失敗してtも変更されないため、操作1〜3は「強力」と見なすことができます。何かがスローtされても、変更されXず、スマートポインターが所有しているためリークしません。

その後、我々はコピー作成t2t何かがスローした場合、7に操作4からこのコピーに、そして仕事をt2修正されたが、その後、tまだ元のです。私達はまだ強い保証を提供します。

その後、我々はスワップtt2。スワップ操作はC ++ではnothrowでなければならないので、作成したスワップがnothrowでないことを期待しましょうT(そうでない場合は、nothrowに書き換えてください)。

したがって、関数の最後に到達すると、すべてが成功し(戻り値の型は必要ありません)、tその例外的な値になります。失敗した場合tでも、元の値のままです。

現在、強力な保証を提供することは非常にコストがかかる可能性があるため、すべてのコードに強力な保証を提供するように努めないでください。 、 じゃやれ。関数ユーザーはそれを感謝します。

結論

例外セーフなコードを書くにはある程度の習慣が必要です。使用する各命令によって提供される保証を評価する必要があり、次に、命令のリストによって提供される保証を評価する必要があります。

もちろん、C ++コンパイラは保証をバックアップしません(私のコードでは、保証は@warning doxygenタグとして提供しています)。

通常の障害とバグ

プログラマは、ノーフェイル機能が常に成功することをどのように保証できますか?結局のところ、関数にはバグがある可能性があります。

これは本当です。例外の保証は、バグのないコードによって提供されることになっています。しかし、どの言語でも、関数を呼び出すと、その関数にバグがないことが前提になります。バグを含む可能性から自分自身を守る正気なコードはありません。できる限りコードを記述し、バグがないことを前提に保証を提供します。バグがある場合は修正してください。

例外は例外的な処理の失敗であり、コードのバグではありません。

最後の言葉

さて、問題は「これはそれだけの価値があるのか​​?」です。

もちろん。"nothrow / no-fail"関数を使用して、関数が失敗しないことを知っていることは大きな恩恵です。同じことが「強力な」関数についても言えます。これにより、コミット/ロールバック機能を備えたデータベースのようなトランザクションセマンティクスでコードを記述できます。コミットはコードの通常の実行であり、例外はロールバックです。

次に、「基本」は、提供すべき最低限の保証です。C ++は非常に強力な言語であり、そのスコープにより、リソースリークを回避できます(ガベージコレクターがデータベース、接続、またはファイルハンドルに提供するのが難しいと思われるもの)。

だから、限り私はそれを見るように、それはあるそれだけの価値。

2010-01-29を編集:スローしないスワップについて

nobarは、「例外安全なコードをどのように作成するのか」の一部であるため、かなり関連性があると私が思うコメントをしました。

  • [me]スワップが失敗することは決してありません(スロースワップを作成することもありません)
  • [nobar]これは、カスタム記述swap()関数に適した推奨事項です。ただし、std::swap()内部で使用する操作によっては失敗する可能性があることに注意してください。

デフォルトでstd::swapは、一部のオブジェクトではスローできるコピーと割り当てが作成されます。したがって、デフォルトのスワップがスローされる可能性があり、クラスまたはSTLクラスに対しても使用されます。限り++標準に関してはCとして、スワップ操作のためにはvectordeque、そしてlist、それは可能性があるため、一方、スローされませんmap比較ファンクタが(参照がコピー建設に投げることができるかどうザ・C ++言語、スペシャルエディション、付録E、E.4.3プログラミング.Swap)。

ベクターのスワップのVisual C ++ 2008実装を見ると、2つのベクターのアロケーターが同じ(つまり、通常の場合)の場合、ベクターのスワップはスローされませんが、アロケーターが異なる場合はコピーが作成されます。したがって、この最後のケースでスローされる可能性があると思います。

したがって、元のテキストは引き続き有効です。スローするスワップを記述しないでください。ただし、nobarのコメントは覚えておく必要があります。スワップするオブジェクトにスローしないスワップがあることを確認してください。

2011-11-06を編集:興味深い記事

Dave Abrahamsは、基本/強力/スロー禁止の保証を提供してくれた記事で、STL例外の安全化に関する彼の経験について述べています。

http://www.boost.org/community/exception_safety.html

7番目の点(例外の安全性のための自動テスト)を見てください。そこでは、すべてのケースがテストされることを確認するために自動ユニットテストに依存しています。この部分は質問作者の「あなたはそれが確かだと確信できますか?」に対する優れた答えだと思います

2013-05-31を編集:dionadarからのコメント

t.integer += 1;オーバーフローが発生しないという保証はなく、例外的な安全性はなく、実際には技術的にUBを呼び出す可能性があります。(符号付きオーバーフローはUB:C ++ 11 5/4です。「式の評価中に結果が数学的に定義されていないか、その型の表現可能な値の範囲にない場合、動作は未定義です。」)符号なし整数はオーバーフローしませんが、2 ^#ビットを法とする同値類でそれらの計算を行います。

Dionadarは次の行を参照していますが、実際には未定義の動作があります。

   t.integer += 1 ;                 // 1. nothrow/nofail

ここでの解決策はstd::numeric_limits<T>::max()、加算を行う前に、整数がすでに最大値になっているかどうかを(を使用して)確認することです。

私のエラーは「通常の障害とバグ」セクション、つまりバグに行きます。それは推論を無効にしません、そしてそれは達成することが不可能であるので例外安全なコードが役に立たないことを意味しません。コンピュータの電源オフ、コンパイラのバグ、さらにはバグやその他のエラーから自分を守ることはできません。完璧を達成することはできませんが、できるだけ近づくことを試みることができます。

Dionadarのコメントを念頭に置いてコードを修正しました。


6
どうもありがとう!私はまだ何か違うものを望んでいました。しかし、私はC ++に固執するためのあなたの答えとあなたの詳しい説明を受け入れます。あなたは私の「これにより、C ++コードのどの行も例外に対して脆弱になります」という違反に反対しました。結局、この行ごとの分析は理にかなっています...私はそれについて考えなければなりません。
フルンシ

8
「スワップは決して失敗しません」。これは、カスタムで作成したswap()関数に適した推奨事項です。ただし、std :: swap()は、内部で使用する操作に基づいて失敗する可能性があることに注意してください。
nobar 2010年

7
@Mehrdad::"finally" does exactly what you were trying to achieveもちろんそうです。また、を使用して脆弱なコードを生成するのは簡単なためfinally、「リソースを試してみる」という概念がついに Java 7 導入されました(つまり、C#の10年後using、C ++デストラクタの30年後)。これが私が批判するこのもろさです。に関してはJust because [finally] doesn't match your taste (RAII doesn't match mine, [...]) doesn't mean it's "failing"、ガーベッジコレクト言語はRAIIにインスパイアされたステートメント(C#usingおよびJava try)を追加する傾向があるため、業界はあなたの好みに同意しません。
paercebal 2012

5
@Mehrdad::RAII doesn't match mine, since it needs a new struct every single darn time, which is tedious sometimesいいえ、ありません。スマートポインタまたはユーティリティクラスを使用して、リソースを「保護」できます。
paercebal 2012

5
@Mehrdad:「ラッパーを必要としない可能性のあるもののラッパーを作成することを強制します」-RAII方式でコーディングする場合、いかなる種類のラッパーも必要ありません。リソースはオブジェクトであり、オブジェクトの存続期間はリソースの存続期間です。ただし、私はC ++の世界出身で、現在Javaプロジェクトに取り組んでいます。C ++のRAIIと比較すると、Javaの「手動リソース管理」は重要です。私の意見ですが、Javaはずっと前に「自動メモリ管理」を「自動リソース管理」と交換していました。
Frunsi 2013年

32

C ++で例外セーフコードを作成することは、多くのtry {} catch {}ブロックを使用することほど重要ではありません。コードが提供する保証の種類を文書化することです。

Herb SutterのGuru Of The Weekシリーズ、特に59回目、60回目、61回目を読むことをお勧めします。

要約すると、提供できる例外安全には3つのレベルがあります。

  • 基本:コードが例外をスローしても、コードはリソースをリークせず、オブジェクトは破壊されたままです。
  • 強力:コードが例外をスローしても、アプリケーションの状態は変更されません。
  • スローなし:コードは例外をスローしません。

個人的に、私はこれらの記事をかなり遅くに発見したので、私のC ++コードの多くは間違いなく例外セーフではありません。


1
彼の著書「Exceptional C ++」も良い読み物です。しかし、私はまだEHの概念に疑問を
投げかけよ

8
例外安全性(通常よりおよそRAII)と例外(それらを引く)を扱う+1 OPの融合します
JK。

プロダクション用のC ++コードはほとんど例外なく安全だと思います。
Raedwald

18

私たちの一部は、20年以上にわたって例外を使用しています。PL / Iはそれらを持っています。それらが新しくて危険な技術であるという前提は私には疑わしいようです。


私を誤解しないでください、私はEHに質問しています(またはしようとしている)。そして特にC ++ EH。そして私は代替案を探しています。多分私はそれを受け入れる必要があります(そしてそれが唯一の方法であるなら私はそうします)が、もっと良い代替案があるかもしれないと思います。コンセプトが新しいと思うのでなく、そうです。なく、戻りコードを使用した明示的なエラー処理よりも危険があるます...
Frunsi

1
気に入らない場合は使用しないでください。呼び出す必要のあるものの周りにtryブロックを置き、ye-olde-error-codeを再発明して、それが持つ問題に耐えます。
bmargulies 2009

わかりました。完璧です。EHとエラーコードを使用し、それと共存させます。私は一口です、私は自分でその解決策に来るべきだったのです!;)
フルンシ

17

まず最初に(ニールが述べたように)、SEHはMicrosoftの構造化例外処理です。これは、C ++の例外処理と似ていますが、同一ではありません。実際、Visual Studioで必要な場合は、C ++例外処理有効にする必要があります。デフォルトの動作では、ローカルオブジェクトがすべての場合に破棄されるとは限りません。いずれの場合も、例外処理は、実際にはない困難それだけで違います

今あなたの実際の質問のために。

あなたは本当に例外安全なコードを書いていますか?

はい。私は例外なく安全なコードを目指して努力しています。リソースへのスコープ付きアクセス(たとえば、boost::shared_ptrメモリ、boost::lock_guardロック)にRAIIテクニックを使用して伝道します。一般に、RAIIスコープ保護テクニックを一貫して使用することで、例外安全なコードをはるかに簡単に記述できます。秘訣は、何が存在し、どのようにそれを適用するかを学ぶことです。

あなたの最後の「プロダクションレディ」コードは例外的に安全ですか?

いいえ、安全です。年中無休24時間のアクティビティの例外により、プロセス障害は発生していません。私は完璧なコードではなく、よく書かれたコードを期待しています。例外的な安全性を提供することに加えて、上記の手法はtry/ catchブロックで達成することがほぼ不可能である方法で正確さを保証します。トップコントロールスコープ(スレッド、プロセスなど)のすべてをキャッチしている場合は、例外が発生しても(ほとんどの場合)実行し続けることができます。同じテクニックは、実行し続けるのにも役立ちますあらゆる場所で/ blockを使用せずtrycatchに例外が発生して正しく

あなたはそれがそうであると確信することさえできますか?

はい。あなたは徹底的なコード監査で確信することができますが、実際に誰もそれをしていませんか?定期的なコードレビューと注意深い開発者は、そこに到達するのに長い道のりを歩んでいます。

機能する代替案を知っているか、実際に使用していますか?

私は、上位ビット(ala HRESULTs)のエンコード状態やその恐ろしいsetjmp() ... longjmp()ハッキングなど、長年にわたっていくつかのバリエーションを試してきました。これらは両方とも、実際には完全に異なる方法で故障します。


最後に、いくつかの手法を適用し、例外に対応して実際に何かを実行できる場所を慎重に検討する習慣をつけると、例外的に安全な非常に読みやすいコードになります。これらのルールに従うことで、これを要約できます。

  • 見たいだけtry/catchあなたが特定の例外について何かを行うことができたときに
  • あなたはほとんど生newやを見たくないdeleteコードで
  • 避けstd::sprintfsnprintf一般に、配列-使用std::ostringstreamして配列をフォーマットし、交換するためstd::vectorstd::string
  • 疑わしい場合は、独自にロールする前にBoostまたはSTLの機能を探してください

C ++で記述する予定の場合は、例外を適切に使用する方法を学び、結果コードを忘れることをお勧めします。例外を避けたい場合は、例外を持たない、安全にする別の言語で書くことを検討してください。C ++を十分に活用する方法を本当に学びたい場合は、Herb SutterNicolai Josuttis、およびScott Meyersの本をいくつか読んでください。


"デフォルトの動作では、ローカルオブジェクトがすべての場合に破棄されることは保証されません。" Visual Studio C ++コンパイラのデフォルト設定により、例外が発生した場合に正しくないコードが生成されるということです。本当にそうですか?
Raedwald

「生newまたはdeleteコードで見たいと思うことはほとんどありません」:とは、コンストラクタまたはデストラクタの外を意味していると思います。
Raedwald

@Raedwald-re:VC ++:VC ++のVS2005エディションは、SEH例外がスローされてもローカルオブジェクトを破棄しません。「C ++例外処理を有効にする」をお読みください。VS2005では、SEH例外はデフォルトでC ++オブジェクトのデストラクタを呼び出しません。Win32関数またはCインターフェースDLLで定義されたものを呼び出す場合、SEH例外をスローする可能性があるため(場合によっては)、これを心配する必要があります。
D.Shawley

@Raedwald:re:raw:基本的に、deleteなどの実装以外では使用しないでくださいtr1::shared_ptrnewその使用法がのようなものであれば、使用できますtr1::shared_ptr<X> ptr(new X(arg, arg));。重要な部分は、結果がnewマネージポインターに直接入ることです。ベストプラクティスページでは、boost::shared_ptrベストプラクティスについて説明しています。
D.Shawley

例外の安全性に関する一連のルールでstd :: sprintf(et al)を参照するのはなぜですか?これらは、例外をスローすることを文書化していません。例:en.cppreference.com/w/cpp/io/c/fprintf
mabraham

10

「どの行でもスローできる」という前提の下で、例外セーフなコードを書くことはできません。例外安全なコードの設計は、コードで期待、監視、従い、実装することになっている特定の契約/保証に大きく依存しています。絶対に絶対に保証されていないコードが必要ですスローです。そこには他の種類の例外保証があります。

つまり、例外に対応したコードを作成することは、大部分は単純なコーディングではなくプログラム設計の問題です。


8
  • あなたは本当に例外安全なコードを書いていますか?

まあ、私は確かにするつもりです。

  • あなたの最後の「プロダクションレディ」コードは例外的に安全ですか?

例外を使用して構築された24時間年中無休のサーバーは24時間年中無休で動作し、メモリリークが発生しないと確信しています。

  • あなたはそれがそうであると確信することさえできますか?

コードが正しいことを確認するのは非常に困難です。通常、結果によってのみ行くことができます

  • 機能する代替案を知っているか、実際に使用していますか?

いいえ。例外を使用する方が、プログラミングで過去30年間使用してきたどの代替手段よりも簡潔で簡単です。


30
この答えには価値がありません。
マットジョイナー

6
@MattJoinerこの場合、質問には価値がありません。
Miles Rout 2014年

5

SEH例外とC ++例外の混同はさておき、例外はいつでもスローされる可能性があることを認識し、それを念頭に置いてコードを記述する必要があります。例外安全性の必要性は、主にRAII、スマートポインタ、およびその他の最新のC ++技術の使用を促進するものです。

十分に確立されたパターンに従っている場合、例外安全なコードを書くことはそれほど難しくなく、実際には、エラーを適切に処理するコードを書くよりも簡単です。


3

一般的に、EHは良好です。しかし、C ++の実装は、例外をキャッチするカバレッジがどれほど優れているかを判断するのが非常に難しいため、あまり友好的ではありません。たとえばJavaはこれを簡単にします。起こり得る例外を処理しないと、コンパイラは失敗する傾向があります。


2
の賢明な使用により、はるかに優れていますnoexcept
einpoklum

2

EHハンドラーがない場合はエディターでエラーが発生するため、EclipseとJava(Javaの新機能)を使用することが本当に好きです。そのため、例外の処理を忘れることが非常に難しくなります...

さらに、IDEツールを使用すると、try / catchブロックまたは別のcatchブロックが自動的に追加されます。


5
これが、checked(Java)とunchecked(c ++)の例外の違いです(Javaにも例外がいくつかあります)。チェック例外の利点は、あなたが書いたものですが、そこには独自の欠点があります。さまざまなアプローチとそれらが抱えているさまざまな問題についてGoogleに。
デビッドロドリゲス-ドリベス

2

CやC#のように非表示にするのではなく、メソッドによってスローされるすべての例外を宣言するように強制するJavaなどの言語を好む人もいます。

例外が適切に行われると、エラーを手動でコールチェーンに伝達する必要がない場合を除いて、例外はエラーリターンコードよりも優れています。

そうは言っても、低レベルのAPIライブラリプログラミングでは、例外処理を回避し、エラーの戻りコードに固執する必要があります。

C ++でクリーンな例外処理コードを書くのが難しいのは私の経験です。new(nothrow)たくさん使ってしまいます。


4
そして、あなたはほとんどの標準ライブラリも回避していますか?使うnew(std::nothrow)だけでは十分ではありません。ちなみに、JavaよりもC ++で例外安全なコードを書く方が簡単です:en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization
avakar

3
Javaでチェックされた例外のユーザビリティは、非常に詳しく調べられています。実際、Java以外の言語は、成功とは見なされません。これが、C ++の「throw」ステートメントが廃止されたと見なされ、C#がそれらの実装を真剣に検討したことがない理由です(これは設計上の選択でした)。Javaの場合、以下の文書がenlightningすることができますgoogletesting.blogspot.com/2009/09/...
paercebal

2
C ++で例外セーフなコードを書くことはそれほど難しくなく、一般的にはよりクリーンなコードにつながる傾向があるというのは私の経験です。もちろん、あなたはそれをすることを学ぶ必要があります。
David Thornley、

2

はい、例外セーフなコードを書くために最善を尽くしています。

それは私が目を離さないように気を付けることを意味します線が投げます。誰もができるわけではないので、それを覚えておくことは非常に重要です。重要なのは、標準で定義されている例外の保証について考え、満足するコードを設計することです。

この操作を記述して、強力な例外保証を提供できますか?基本的なもので十分ですか?例外をスローする可能性のある行はどれですか。また、例外がスローされた場合でも、オブジェクトが破損しないようにするにはどうすればよいですか?


2
  • あなたは本当に例外安全なコードを書いていますか?【そんなものはありません。管理された環境がない限り、例外はエラーに対する紙の盾です。これは最初の3つの質問に適用されます。]

  • 機能する代替案を知っているか、実際に使用していますか?[何の代わりに?ここでの問題は、実際のエラーを通常のプログラム操作から分離しないことです。通常のプログラム操作(つまり、ファイルが見つからない)の場合、それは実際にはエラー処理ではありません。実際のエラーの場合、「処理」する方法がないか、実際のエラーではありません。ここでの目標は、何が問題だったかを見つけて、スプレッドシートを停止してエラーをログに記録するか、ドライバーをトースターで再起動するか、ソフトウェアにバグがあり最高のものを期待している場合でも、ジェット戦闘機が飛行を続けることができるように祈ることです。]


0

多くの人(私はほとんどと言ってもいいでしょう)がします。

例外について本当に重要なのは、処理コードを何も記述しない場合、結果は完全に安全で行儀がよいということです。パニックになりたくても安全です。

安全でないものを取得するには、ハンドラーで積極的にミスをする必要があり、catch(...){}のみがエラーコードを無視することと比較されます。


4
違います。例外セーフでないコードを書くのはとても簡単です。例:f = new foo(); f->doSomething(); delete f;doSomethingメソッドが例外をスローした場合、メモリリークが発生しています。
クリストファージョンソン

1
プログラムがいつ終了するかは問題ではありませんよね?実行を継続するには、例外を積極的に飲み込む必要があります。まあ、クリーンアップなしの終了がまだ受け入れられない特定のケースがありますが、そのような状況では、プログラミング言語とスタイルで特別な注意が必要です。
ima

C ++でもマネージコードでも、例外を無視することはできません(処理コードを記述しないでください)。安全ではなく、正常に動作しません。たぶんいくつかのおもちゃのコードを除いて。
Frunsi、2009

1
アプリケーションコードの例外を無視しても、外部リソースが関係している場合、プログラムは依然として適切に動作しない可能性があります。確かに、OSはファイルハンドル、ロック、ソケットなどを閉じることを考慮します。ただし、すべてが処理されるわけではありません。たとえば、書き込み中に不要なファイルが残ったり、ファイルが破損したりする場合があります。例外を無視すると、Javaで問題が発生し、C ++ではRAIIで作業できます(ただし、RAIIテクニックを使用する場合は、例外を気にするため、おそらくそれらを使用します)...
Frunsi

3
私の言葉をねじらないでください。私は「処理コードを記述しない場合」と書きました-まさにそれを意味しました。例外を無視するには、コードを記述する必要があります。
ima
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.