0

注: RedHat Linux 6.3 で gcc 4.4.7 を使用しています。以下の例の質問は、A::doSomething()例外がデストラクタからスローされるべきかどうかではなく、スローされた最初の例外に対して GCC が行うことに関するものです。

次のコードでは、関数は 2 つの例外A::doSomething()で終了します。デストラクタlogic_errorの 2 番目はfromを上書きしているようです。プログラムからの出力を以下に示します。logic_error~A()logic_errorA::doSomething()

logic_error私の質問は、によって投げられたのはどうしたことですかA::doSomething()。それを回復する方法はありますか?

#include <iostream>
#include <stdexcept>

#include <sstream>

using namespace std;

class A
{
public:
A(int i):x(i) {};
void doSomething();

~A() {
    cout << "Destroying " << x << endl;
    stringstream sstr;
    sstr << "logic error from destructor of " << x << " ";
    throw logic_error(sstr.str());
    }

private:
int x;
};

void A::doSomething()
{
A(2);
throw logic_error("from doSomething");
}


int main()
{

A a(1);
try
{
    a.doSomething();
}
catch(logic_error & e)
{
    cout << e.what() << endl;
}

return 0;
}

出力は次のとおりです。

Destroying 2
logic error from destructor of 2
Destroying 1
terminate called after throwing an instance of 'std::logic_error'
what():  logic error from destructor of 1
Aborted (core dumped)
4

1 に答える 1

1

編集: http://www.compileonline.comでの実験観測された動作も奇妙だと思います。システムが停止する必要があることに気付く前に、メインスレッドが先に実行され、A(1) が破棄されている間に、terminate() が別のスレッドまたは非同期で呼び出されたように見えます。

C++03 を読み直しても、15.5.1p1b3 までは terminate を呼び出す必要があり、p2 まではそれ以上何も許可されていません。ここでは gcc の動作が不適合に見えます。

http://coliru.stacked-crooked.com/の新しい gcc 出力は次のとおりです。

Destroying 2
terminate called after throwing an instance of 'std::logic_error'
  what():  logic error from destructor of 2 

これは予想されるものです (最後の 2 行はありませんが、terminate() 呼び出しの後の追加情報と見なすことができます)。


実装を適合させるための理論:

そのようなコードを書くとどうなるかについては、 GOTW#47SO スレッドを読んでください。

要約すると、言語ルールは、例外が正常にスローされた場合 (コピーされ、スタックの巻き戻しが開始された場合)、それがキャッチされる前に別の例外がスローされた場合、terminate() が呼び出されるというものです。意図しない結果で終了するため、この問題を回避するためにコードを再配置することを検討してください。

于 2013-06-09T23:52:38.927 に答える