17

std::exceptionそのコンストラクタがである必要がありますthrow()。それでも、引数としてstd::runtime_erroraを受け入れます。これは、どこかに格納されていることを示します。したがって、割り当てまたはコピーの構築はどこかで行われている必要があります。そして、のために、それは操作ではありません。std::stringstd::stringstd::stringnothrow

では、どのようにruntime_error::runtime_error会うのthrow()でしょうか?

(コンテキストとして、例外タイプを実装していてstd::string、呼び出しサイトから数秒を保存したいのですが、正しく実行したいのですが...)

4

2 に答える 2

9

(これは、最小限のテストケースでも同じです。)


runtime_error::runtime_error(string const&)会う必要はありませんthrow()

を継承したりオーバーライドしたりすることはなくexception::exception()stringのコピーコンストラクターが呼び出されるまでexception::exception()に完了しています。

コピーしstringて例外がスローされた場合、これは巻き戻さruntime_error::runtime_error(string const&)れてから、を呼び出すと思いますexception::~exception()


派生ctorがベースctorの例外指定子を満たす必要がないことを直接示すことは困難ですが、次の節(例外をベースコンストラクターに渡すのではなく、ベースのデストラクタがどのように呼び出されるかを説明しています)によって強く暗示されます。 )::

[2003: 15.2/2] 部分的に構築または部分的に破棄されたオブジェクトでは、完全に構築されたすべてのサブオブジェクトに対してデストラクタが実行されます。つまり、コンストラクタが実行を完了し、デストラクタがまだ実行を開始していないサブオブジェクトに対して実行されます。自動配列の要素のコンストラクターが例外をスローした場合、その配列の構築された要素のみが破棄されます。オブジェクトまたは配列がnew-expressionで割り当てられた場合、一致する割り当て解除関数(3.7.3.2、5.3.4、12.5)が呼び出され、オブジェクトが占有しているストレージが解放されます。

あなたが推測した(そして私が最初に推測した)シナリオにさえ近づく唯一の箇所は次のとおりです。

[2003: 15.4/3]仮想関数に例外仕様がある場合、派生クラスのその仮想関数をオーバーライドする関数の定義を含むすべての宣言は、基本クラスの仮想関数の例外仕様によって許可される例外のみを許可するものとします。

しかし、明らかにexception::exception()仮想関数ではなく、明らかにruntime_error::runtime_error(string const&)それをオーバーライドしません。

(このシナリオ仮想デストラクタに適用されることに注意してください。したがって、 libstdc ++ではであることがわかりますruntime_error::~runtime_error()throw())。

于 2011-07-28T18:50:58.733 に答える
7

更新、2015年:

それでも、引数としてstd::runtime_erroraを受け入れます。これは、どこかに格納されていることを示します。したがって、割り当てまたはコピーの構築はどこかで行われている必要があります。そして、のために、それは操作ではありません。std::stringstd::stringstd::stringnoexcept

runtime_error(およびlogic_error)は、型の引数を受け入れるためにのみ必要ですstd::string const &コピーする必要はありません。

あなた自身の危険でこれらの過負荷を使用してください。LLVMlibc++はストレージを提供しません。

一方、GNU libstdc ++は、メモリ不足を回避するために慎重につま先立ちします。文字列の内容をコピーしますが、新しいではなく、例外ストレージスペースにコピーしますstd::string

それでも、std::string&&オーバーロードを追加し、shipを使用して、rvalueによって渡されfriendた引数の内部バッファーを採用し、例外ストレージスペースも節約します。std::string

それがあなたの本当の答えです:「もしあったとしても、非常に注意深く」。

std::runtime_errorsを独自の例外クラスのメンバーとして使用し、それぞれ1つの文字列を格納することで、GCCの寛大さを活用できます。ただし、これはClangではまだ役に立ちません。


元の回答、2011年。これはまだ当てはまります。

スタックの巻き戻し中の例外によりterminate、が呼び出されます。

ただし、スローされるオブジェクトの作成はアンワインドの一部ではなく、throw式の前のコードと同じように扱われます。

std::runtime_error::runtime_error( std::string const & )をスローするstd::bad_allocと、runtime_error例外は失われ(存在しなかった)、bad_alloc代わりにが処理されます。

デモンストレーション: http: //ideone.com/QYPj3

呼び出しサイトからのを格納する独自のクラスについては、std::string§18.8.1/2に従う必要があります。

クラス例外から派生する各標準ライブラリクラスTには、公的にアクセス可能なコピーコンストラクタと、例外なしで終了しない公的にアクセス可能なコピー割り当て演算子が必要です。

スタックからスレッドの例外ストレージへのコピーは例外の影響を受けやすいため、これが必要です。§15.1/7:

スローされる式の評価が完了した後、例外がキャッチされる前に、例外処理メカニズムが例外を介して終了する関数を呼び出す場合、std :: terminateが呼び出されます(15.5.1)。

したがって、最初のコピーのshared_ptr< std::string >にコピーをサニタイズするには、またはそのようなものを使用する必要があります。

于 2011-07-28T19:44:57.740 に答える