13

情報が不足しているため、文字列をスローしてはいけないと聞きました。キャッチするとは思わない例外をキャッチします。例外をスローするための良い方法は何ですか? 基本例外クラスを継承しますか? 例外は多いですか、それとも少ないですか。MyExceptionClass& または const MyExceptionClass& を実行しますか? など。また、デストラクタで例外をスローしてはならないことも知っています

契約による設計と、いつ例外をスローするかを理解していることを付け加えます。例外をスローする方法を尋ねています。

4

12 に答える 12

12

私の意見では、「約束」を守ることができない場合、または「契約」を破る必要がある場合、関数は例外をスローする必要があります。関数の署名 (名前とパラメーター) によって、そのコントラクトが決まります。

次の 2 つのメンバー関数が与えられた場合:

const Apple* FindApple(const wchar_t* name) const;
const Apple& GetApple(const wchar_t* name) const;

これらの関数の名前とその戻り値は、FindAppleの場合、関数が正しいリンゴが見つからなかった場合に NULL を完全に返すことができることを示していますが、 GetAppleの場合は、リンゴが返されることを期待しています。 . その 2 番目の関数がその約束を守れない場合、例外をスローする必要があります。

例外は、関数がこれらの状態を報告する他の方法がない例外的な状態を意味します。それを約束の一部にすることにした場合(読み取り:関数シグネチャ)、例外をスローせずにその状態を報告できます。

FindAppleの場合、「適切なリンゴが見つからない」という状態をどのように処理するかは、呼び出し元が決定することに注意してください。これは、もはや例外的な状態ではないためです。

すべての例外を回避しようとするかもしれませんが、それは、考えられるすべての例外条件を考慮する必要があり、代わりに呼び出し元に負担をかけることを意味します。次に、呼び出し元は「エラー状態」をチェックする必要があります。

最終的に、例外を処理する必要がありますが、特定の条件を有効な方法で処理する方法を知っている呼び出し元だけが例外を処理する必要があります。そして、これは可能な限り広い解釈で意味します。あきらめたサービスは後で再試行します、役立つエラーメッセージを提供する UI、「おっと」画面を表示するがうまく回復する Web アプリなど...などです。 .

デイブ

于 2009-02-17T11:22:18.943 に答える
9

基本的なことの 1 つは、例外的な状況にのみ例外を留保することです。フロー制御には使用しないでください。たとえば、「ファイルが見つかりません」は例外ではなく、エラー コードまたは戻り値である必要があります (ファイルが存在しなければならないもの (構成ファイルなど) でない限り)。ただし、処理中にファイルが突然消えた場合は、例外をスローすることをお勧めします。

例外を控えめに使用する場合、より深い層からコンテキスト内で理解できない例外を受け取ることを避けるために、コードを try-catch -spaghetti に変換する必要はありません。

于 2009-02-17T10:47:52.660 に答える
4

標準例外を使用してください。特定のエラーがある場合は、戻り値でそれを回避してください。例外を使用する必要がある場合は、Exception から継承するカスタム例外を定義し、カスタム メッセージを作成します。

于 2009-02-17T10:43:44.027 に答える
3

場合によっては、エラー コードを返せないことがあります。エラー状況が発生したときの正確なコンテキストが必要な場合。エラーステータスを3レベル上に伝播する必要がある場合-コンテキストが失われます。

この状況では、カスタム クラスが最適なソリューションです。私はこのアプローチを使用して、独自のインライン クラスを定義します (.cpp はありません。.h のみです)。例:

class DeviceException {
    ;
}

class DeviceIOException: public DeviceException {
    DeviceIOException(std::string msg, int errorCode);
}

次に、例外の種類とそこに含まれる情報によって、例外を判断/対応することができます。

于 2009-02-17T11:05:13.570 に答える
1

私は常に例外をスローし、それが発生した場所とその原因を示すメッセージを表示します。

throw NException("Foo::Bar", "Mungulator cause a stack overflow!");

その後、これらの文字列をメッセージボックスなどで使用できます。

私はいつも経由でキャッチします

catch (NException& ex) { ... }

Windowsを実行している場合は、エラー値を渡して、関数にエラーメッセージを取得させることができます。これの最も良い例は、JeffreyRichterによるC/C++経由のWindowsです。

于 2009-02-17T11:19:54.487 に答える
1

ポインターをスローすると、スローされたオブジェクトの所有権が複雑になるため、おそらく良いことではありません。クラスタイプの例外は、例外の理由に関するより多くの情報を含めることができるという理由だけで、おそらく基礎よりも優れています。

クラスまたはクラス階層を使用する場合、考慮すべき点がいくつかあります。

  1. 例外オブジェクトのコピー コンストラクターとデストラクターの両方が例外をスローしてはなりません。もしそうなら、あなたのプログラムはすぐに終了します.(ISO 15.5/1)

  2. 例外オブジェクトに基本クラスがある場合は、パブリック継承を使用してください。基本クラスがアクセス可能
    である場合、ハンドラーは基本クラスの派生に対してのみ選択されます。(ISO 15.3/3)

  3. 最後に、(すべての例外の種類について) スローされる式自体がスローされる例外にならないようにします。

例えば:

class Ex {
public:
  Ex(int i) 
  : m_i (i)
  {
    if (i > 10) {
      throw "Exception value out of range";
    }
  }

  int m_i;
};


void foo (bool b) {
  if (! b) {
     // 'b' is false this is bad - throw an exception
     throw Ex(20);    // Ooops - throw's a string, not an Ex
  }
}
于 2009-02-17T11:29:27.397 に答える
1

std::exception から派生した例外クラスを常にスローする必要があります。これにより、インターフェイスに一定の一貫性が与えられ、これらのメソッドまたは関数のクライアントにより多くの柔軟性が与えられます。たとえば、catch all ハンドラーを追加する場合は、

catch(std::例外& e)
ブロックして、それで終わりです。(ただし、スローされる可能性のあるすべてのコードを制御しないと、それを回避できないことがよくあります)。

標準で提供されている例外 (つまり、std::runtime_error) のみをスローする傾向がありますが、ハンドラーにさらに細分性を持たせたい場合は、std::exception から独自の例外を自由に派生させてください。C++ FAQ liteを参照してください。

また、一時的なものをスローし、参照によってキャッチする必要があります (コピー ctor がキャッチ サイトで呼び出されるのを避けるため)。誰がメモリをクリーンアップする必要があるのか​​ 不明であるため、ポインターのスローも眉をひそめます。C++ FAQ Liteもこれに対応しています。

于 2009-02-18T00:38:34.253 に答える
0

C++ FAQ より[17.12] 何を投げるべきか? :

一般に、組み込みではなく、オブジェクトをスローするのが最善です。可能であれば、クラスから (最終的に) 派生するクラスのインスタンスをスローする必要がありますstd::exception

...と

最も一般的な方法は、temporary: をスローすることです (次の例を参照してください) 。

于 2013-02-04T16:02:02.680 に答える
0

現在のプロジェクトでは、メイン プログラム ループで実行できる適切なアクションについて考えました。基本的なプログラムは XML メッセージを受け取り、その情報をデータベースに保存します (その間にかなりの量の処理が行われます)。

  1. 入力に問題があることを示すデータ エラー。適切なアクションは、メッセージをログ ディレクトリに保存することですが、処理はしません。
  2. 一部のサブコンポーネント (入力キュー、SQL データベース、JNI ライブラリなど) が誤動作していることを示すインフラストラクチャ エラー。数分間スリープしてから、再接続します。
  3. 一部のアスペクト構成が機能しないことを示す構成エラー。プログラムを終了します。

最初の項目はチェック済み例外です。これは、データ チェックがメソッドのインターフェイスの一部であると見なしたためです。メイン ループはサブコンポーネントの実装を認識できないため、その他はチェックされません。たとえば、実装で SQL データベースを使用したり、単にデータをメモリに保持したりできます。呼び出し側は知る必要はありません。

于 2009-02-17T10:52:51.477 に答える
0

すでに述べたように、それらは例外的な状況でのみ使用してください。

ユーザーが例外のスローを回避する方法を常に提供します。メソッドがある場合、次のように何か問題が発生した場合にスローされます。

public void DoSomethingWithFile() {
    if(!File.Exists(..))
        throw new FileNotFoundException();
}

ユーザーが呼び出す別のメソッドを提供します。

public bool CanDoSomething() {
    return File.Exists(..);
}

このようにして、呼び出し元は必要に応じて例外を回避できます。何か問題が発生した場合はためらわずにスローします。「すばやく失敗します」が、常に例外のないパスを提供します。

また、例外クラスの階層をフラットに保ち、InvalidStateException や ArgumentNullExcpetion などの標準例外を確認してください。

于 2009-02-17T11:38:39.760 に答える