7

インスピレーションを得ることができるように、適切に設計された堅牢な例外メカニズムを備えたオープンソースの C++ アプリケーションを知っている人はいますか? 私が目にするほとんどのコード/例は、次のような疑わしいことを行います。

  1. メッセージ文字列を引数としてオブジェクトをスローします。例外を致命的とマークするため、間違っているように見えます。上位のユーザーに表示されるエラーメッセージは、クライアントコードが例外を処理しようとする余地がほとんどありません。例外が致命的であっても、ロケール (言語) が異なるなどの理由で、スローの時点でメッセージをフォーマットすることは、私には悪い考えのように思えます。
  2. 基本例外クラスから派生した多数の異なる例外クラスを使用します。うまくいかない可能性のあるすべてのこと(ファイルを開く、ファイルを読み取る、ファイルを書き込む、スレッドを作成するなど)に対して新しいクラス/タイプを導入するのは間違っていると感じています。基本型を使用して未処理の例外をすべて最上位レベルでキャッチすると、意味のあるエラー メッセージを表示するために必要な型情報が失われます。
  3. コンポーネント/ライブラリごとに基本例外クラスから派生した 1 つの例外クラスを使用し、引数としてエラー コードを指定して、正確なエラーを示します。基本型でキャッチするとあいまいになります。(エラーコード「3」をキャッチしたのは誰ですか?)...

正しい方向へのいくつかの指針は大歓迎です。

4

1 に答える 1

6

これら 3 つすべてに対処するには、.NET から派生した独自のカスタム例外をスローするのが最善であることがわかりましたstd::runtime_error。このような:

#include <exception>

class ChrisAException : public std::runtime_error
{
      /// constructor only which passes message to base class
      ChrisAException(std::string msg)
      : std::runtime_error(msg)
      {

      }
}

文字列を受け入れることができます。これは常に次のような形式で入力します (x負の値は有効な入力ではなく、それを呼び出す何かがエラーであると仮定します)。

#include "ChrisAException.h"

void myfunction(int x)
{

    if(x < 0) 
    {
        throw ChrisAException("myfunction(): input was negative!");
    }

    // rest of your function
} 

この場合、これらの例外の文字列は、エンド ユーザーよりもプログラマー向けであることに注意してください。障害が発生したときにロケールで意味のあるものを表示するのは、インターフェースの仕事のプログラマーです。例外の文字列は、ログに記録するか、デバッグ時に表示できます (望ましい!)

このようにして、最終的に次の方法でキャッチできます。

try
{
      // high level code ultimately calling myfunction

}
catch(ChrisAException &cae)
{
       // then log cae.what()
}
catch(std::runtime_error &e)
{
       // this will also catch ChrisAException's if the above block wasn't there
}
catch(...)
{
      // caught something unknown
}

個人的には、あまりにも多くの種類の例外を派生させたり、エラー コードを与えたりするのは好きではありません。文字列メッセージに報告をさせます。

一般に、私は C++ 例外を「プログラムで何か問題が発生した」ことを意味するために使用し、通常のユース ケースを処理しないようにします。したがって、私にとって、アルゴリズムの実行中にスローされた例外は、「何かがうまくいかなかったことをユーザーにフラグを立てる」か「ユーザーに知らせない」ことを意味します (そのコードがユーザーの行動にとってどれほど重要であったかによって異なります) が、確実にログに記録しますそして、プログラマーに何らかの形で知らせます。

私は C++ の例外を、本質的にプログラミング エラーではないケース (たとえば、ある種の間違ったロジックや何かが間違って呼び出されているなど) を処理するために使用しません。たとえば、DVD 書き込みプログラムのドライブに空の DVD がないなどの通常のプログラム状況を処理するために C++ 例外を使用することはありません。そのために、ユーザーが空の DVD があったかどうかを (おそらくダイアログなどで) 知ることができる明示的なリターン コードが必要です。

try-catchC++ 例外処理の一部は、スタックをブロックまでアンワインドすることであることに注意してください。つまり、プログラムで起こっていることを中止し、スタックをクリーンアップします。私の DVD の例のようなものの場合、スタックの多くを巻き戻したくはないはずです。それは壊滅的ではありませんでした。ユーザーに知らせてから、もう一度試してもらう必要があります。

しかし、繰り返しになりますが、これは経験と私の読書に基づいて、C++ 例外を使用する私の好みの方法です。そうでなければ、私は意見を受け入れます。

編集:コメンターのアドバイスに基づいて変更std::exceptionされました。std::runtime_error

于 2012-04-26T00:00:07.893 に答える