12

使用時にキャッチしたい例外をスローする可能性のある関数を含むクラスを構築したいと考えています。標準の例外クラスから my_exception を継承します。what() 関数を実装して、プライベート文字列変数に格納されている文字列を返すようにします

ios_base::failure を使用して iostream ライブラリで行われているように、例外をネストされたクラスとして定義する方がよいと思います。

あまり確信が持てないのは、my_expetion のオブジェクトをどこでどのように定義する必要があるかです。iostream 関数の内部コードを見て、それがどのように行われたかを確認できればと思います。私はいくつかのオプションについて考えました:

  1. 例外の理由ごとに、文字列を取得してプライベート文字列ポインターに保存するコンストラクターを使用して、my_exception の静的インスタンスを定義できます。

  2. 例外の理由ごとに、my_exception から継承する別のクラスを定義し、定数文字列 (理由) を返す関数として what を実装できます。その例外サブクラスのそれぞれのインスタンスを保持したり、型をスローしたりできます。ところで、通常、インスタンスではなくタイプをスローするのはいつですか?

  3. 私はそれが間違っていると思います: 例外をスローしたいたびに、文字列を取得するコンストラクターで新しい my_exception を作成します。これは Java で行われますが、例外をどこかで削除する必要があるため、C++ では問題になると理解しています。右?

1枚目が正しいと思いますよね?これ以上の標準オプションはありますか?

どうもありがとうございました!

4

3 に答える 3

18

簡単な答え: ポインターとしてではなく、オブジェクトとして例外をスローする必要があります。それらを参照としてキャッチします。

より長い答え: あなたがリストするオプションはすべて有効です。一般に、ポインターではなくオブジェクトをスローする理由は、例外がキャッチされたときに自分自身とクライアントに与える選択肢のためです。

ポインターでキャッチcatch (my_exception* e)すると、メモリを削除する必要があるかどうかがわかりません。

値でキャッチするcatch (my_exception e)と、例外オブジェクトが最終的に他の派生クラスを持つ基本クラスになる場合、スライスのリスクがあります。

参照によるキャッチには、これらの問題はありません。書けばcatch (my_exception& r)、多態的なオブジェクトをキャッチでき、メモリの解放について心配する必要はありません。

したがって、他の質問に答えるには、スローするときに一時オブジェクトをスローするだけです: throw my_exception(). これにより、(おそらく) スローされたときにコピーされ、参照によってキャッチされ、catch ブロックの最後でスコープ外になると自動的に破棄される一時オブジェクトが作成されます。(これは実際には、値によるキャッチよりも参照によるキャッチの別の利点です。値によるキャッチは、キャ​​ッチされるとさらに別のコピーを作成するためです。)

他の派生例外クラスに関しては、スタイルの選択です。異なる what() 実装で my_exception から派生することは、かなり標準的です。文字列やインスタンスを静的オブジェクトに格納することに凝る必要があるとは言いません。それらは小さく、例外がスローされたときにスタックを巻き戻すプロセスと比較して、それらを構築するのにほとんど時間がかかりません。

于 2011-05-28T04:53:28.280 に答える
12

std::runtime_error から派生する場合、文字列を格納するために独自のメンバーを定義する必要はありません。これは std::exception (std::runtime_error のベース) で自動的に行われます。例外が文字列を格納する方法は定義されていませんが、常に機能するはずです。

#include <stdexcept>
#include <string>

struct MyException: public std::runtime_error
{
    MyException(std::string const& message)
        : std::runtime_error(message + " Was thrown")
    {}
};
于 2011-05-28T06:20:35.860 に答える
0

どのオプションにも問題はありません。new例外オブジェクトを削除する必要がないため、ローカル変数を作成して を使用しない限り、番号 3 は問題ありません。スローするとすぐに破棄されます。throwスローされた例外は、実際にはステートメントに指定したもののコピーになるため、コピー コンストラクターとコピー オペレーターを作成する必要があります。

オプション 1 は、通常は必要ないため、一般的ではありません。

オプション 2 では、スローするクラスのインスタンスを作成します。型をスローすることはできず、型のインスタンスのみをスローできます。

于 2011-05-28T04:52:13.073 に答える