2012-07-13 7 views
7

C++で長年にわたり科学ソフトウェアをコーディングしても、私はまだ例外に慣れていないようで、いつ使用するべきかわかりません。私は、プログラムの流れを制御するためにそれらを使用することは大きなノーではないことを知っていますが、以下の例を考えてみましょう(画像マスクを表すクラスから抜粋し、ユーザーがポリゴンとして領域を追加できるようにします):C++で例外を使用するかどうかわからない

class ImageMask 
{ 
public: 
    ImageMask() {} 
    ImageMask(const Size2DI &imgSize); 

    void addPolygon(const PolygonI &polygon); 

protected: 
    Size2DI imgSize_; 
    std::vector<PolygonI> polygons_; 
}; 

このクラスのデフォルトコンストラクタは、イメージサイズが定義されていない無駄なインスタンスを作成します。ユーザーがそのようなオブジェクトにポリゴンを追加できるようにする必要はありません。しかし、私はそのような状況をどのように処理するかは分かりません。サイズは未定義であり、addPolygon()が呼び出されると、すべきI:

  1. サイレント・リターン、
  2. このクラスを使用してコードに違反を検出し、リリース前にそれらを修正する
  3. のassert(imgSize_.valid)、
  4. 例外をスローしますか?

ほとんどの場合、私の気分に応じて1)または2)のいずれかに行きます。私には例外がありますが、そのような単純なシナリオでは例外が高価で扱いにくく過度です。いくつかの洞察をお願いしますか?

+4

デフォルトの構成を防止しますか?無効な 'ImageMask'インスタンスが作成されないようにします。 – hmjd

+1

なぜデフォルトコンストラクタが必要ですか? –

+0

デフォルトコンストラクタは、その型のオブジェクトを特定のコンテナに入れることができるように便利です。 – MadScientist

答えて

6

一般的なルールは、目的の操作を実行できないときに例外をスローすることです。したがって、あなたのケースでは、addPolygonが呼び出され、サイズが未定義または不一致のときに例外をスローするのは意味があります。

サイレントリターンは、ほとんど常に間違ったことです。 assertは優れたエラー処理手法ではありません(これは設計/文書化の技術です)。

しかし、あなたのケースでは、エラー状態を不可能にするためのインターフェースの再設計が良いかもしれません。例えば、このような何か:私に

class ImageMask 
{ 
public: 
    // Constructor requires collection of polygons and size. 
    // Neither can be changed after construction. 
    ImageMask(std::vector<PolygonI>& polygons, size_t size); 
} 

またはこの

class ImageMask 
{ 
public: 
    class Builder 
    { 
    public: 
     Builder(); 
     void addPolygon(); 
    }; 

    ImageMask(const Builder& builder); 
} 

// used like this 
ImageMask::Builder builder; 
builder.addPolygon(polyA); 
builder.addPolygon(polyB); 
ImageMask mask(builder); 
1

のような、1にはオプションではありません。それが2か3かどうかは、イメージマスクをデフォルトで作成してからポリゴンを追加するかどうかにかかわらず、プログラム/ライブラリの設計によって異なります。これは重要な設計上の決定です。 Matthew Wilsonのthis articleを読むことをお勧めします。あなたはより多くのオプションを持っている

注:

  • は::常にSTDを呼び出して、独自のアサートを発明終了し、(他の人がすでに指摘したように)追加のログ
  • は、デフォルトコンストラクタを無効にしない - これがあります私のお気に入り
2

何か役に立たない状態のデータを作成することはできません。空ではないポリゴンが必要な場合は、空のポリゴンを作成しないようにしてください。

私は決して静かなリターンを使用しません。なぜなら、彼らはバグを隠しているため、バグがはるかに複雑であることがわかります。

私は、プログラムにバグがある場合にのみ、そのプログラムが存在する可能性があることを検出するとアサーションを使用します。あなたの例では、Size2DIを取るc'torをチェックインすると、このサイズは空ではなく、格納されたサイズが空でないかどうかを確認するよりも、バグを検出するのに便利です。アサーションには副作用があってはならず、ソフトウェアの動作を変更することなく、アサーションを削除する必要があります。私はそれらを非常に便利に見つける、自分のバグを発見し、オブジェクト/関数などの現在の状態を文書化する。

これはおそらく、実行時エラーは関数の呼び出し元従来の戻り値を使用します。このエラー状況は、コールスタックのいくつかの関数呼び出しで伝えなければならない可能性が非常に高いですが、私は例外を優先します。疑いの余地は2つの機能を提供します。

種類が についてトルステン・

1
  1. は「サイレント返す」 - それは「ビッグノーノー」本当です。プログラムは何が間違っているかを知るべきです。
  2. "assert" - 2番目のルールは、通常のプログラムのフローを復元できなかった場合にのみ使用するアサートです。
  3. 「例外をスローする」 - はい、この権利と優れた技術。単に例外安全性に注意してください。 GotWには例外安全なコーディングに関する記事が多数あります。

恐れ入りますが、例外はありません。彼らは噛まない。 :)このテクニックを十分に活用するなら、強力なコーダーになるでしょう。 ;)

+0

面白いことに、Javaでは例外が非常に簡単に使えますが、C++では誤解されています。 – marcinj

+0

驚くことはありません。 Javaはあなた自身のメモリを管理します。 Cpp-developerは、彼の記憶を彼の脳によって管理することができます(そして、幸いにも、または残念なことに - 必要があります)。 ;) –

関連する問題