2013-02-08 15 views
7

exception_ptrが何をするか検討している間は、C++ 11標準は、(18.8.5/7)と言うこと:データ競合を導入してはならない同じ例外オブジェクトを参照してくださいexception_ptrオブジェクト上rethrow_exceptionのrethrow_exceptionは本当にコピーではなく同じ例外オブジェクトをスローすることができますか?

使用。 [注意:rethrow_exceptionは同じ例外オブジェクト(というよりコピー)を再スローした場合、その再スロー例外オブジェクトへの同時アクセスは、データ競合を導入することができる...

私はこの奇妙な「ノートケースを見つけることができません。 rethrow_exceptionの記載された効果は「例外:pが参照する例外オブジェクト」であるが15.1/3であるため、「例外を投げる」ことは例外オブジェクトと呼ばれる一時オブジェクトをコピー初期化することを要求する。 "

奇妙なメモは、rethrow_exceptionがこのコピー初期化をスキップすることを意味します。しかし、これは本当に可能ですか?

+0

おそらく動いていますか? –

+0

しかし、 'std :: rethrow_exception'は' throw x; '式を使って実装することはできません。 (ただし、 'throw;と似ています。) – aschepler

答えて

3

はい、標準の欠陥のようです。オペランドなしで再スロースロー発現即ちthrow;ため、15.1p8は言う:

ないオペランドとスロー発現が現在処理例外を再スロー。例外は既存の例外オブジェクトで再アクティブ化されます。新しい例外オブジェクトは作成されません。 [...]

つまり:

​​

current_exceptionコピー現在処理例外オブジェクトの実装は、rethrow_exceptionコピーかどうかを指示する方法はありません場合は、それはを参照している場合例外オブジェクトは、その後、我々は確認することができます。

#include <exception> 
#include <iostream> 
int main() { 
    std::exception_ptr p; 
    try { 
     try { 
     throw std::exception(); 
     } catch(...) { 
     p = std::current_exception(); 
     std::cout << (p == std::current_exception()) << ' '; 
     std::rethrow_exception(p); 
     } 
    } catch(...) { 
     std::cout << (p == std::current_exception()) << '\n'; 
    } 
} 

私は版画1 1上でそれを試してみた全ての実施を。 コピーの場合は0 0が許可されます。 0 1は明らかに不可能ですが、現在の状態の標準は1 0が必要です。この修正は、rethrow_exceptionexception_ptrが指し示す例外オブジェクトをコピーすることを許可または義務づけている15.1p8と同様の言語で18.8.5p10を明確にすることになります。

ほとんど例外:標準で仕様がちょうどタイプ(例外:bad_alloc)の名​​前または不定冠詞(例外:タイプ...の例外)を使用します。明確な記事を使用するための他の唯一の例外仕様はfuture::getshared_future::getのものなので、どの解像度でもこれらの問題に対処する必要があります。

+0

さらなる調査の後、私はLWGがこの場合にコピーを強制することを提案する問題を発見しました(issue#1369)。彼らはそれに対して解決したように見え、実装がどのように振る舞っているかを確認します。私は、あなたが提案したような明確化は理にかなっていると信じています。 – soulie

2

はい、可能です。例外処理メカニズムは、もともとスローされたオブジェクトのコピーをすでに持っています。通常、exception_ptrは、そのコピーの参照カウントを管理するスマートポインタとして実装されます。 一般要件として

は、一般的な要件を持つ特定の要件の競合は、特定の要件が勝てば。

+0

AFAIKの注釈は規範的なものではないので、再スローさせると、新しいコピーが作成されるはずです。 – soulie

+0

@twicker - 正しく指定されていない可能性があります。 '' 'exception_ptr'はもともとライブラリ専用拡張であり、ランタイム例外サポートの拡張が必要でしたが、言語の変更は必要ありませんでした。新しいコピーを必要とするということは、オブジェクトのコピーコンストラクタへのポインタを格納する方法を必要とすることを意味します。それは技術的に実現可能ですが、古いオブジェクトを再利用するほうがはるかに簡単です。実際には違いはありません。呼び出されたかどうかを記録するコピーコンストラクタを記述することもできますが、それは実際のコードには影響しません。 –

3

throw x;と言うとき、例外オブジェクトはxと同じタイプですが、コピーです。

std::rethrow_exception(p);と言うとき、例外オブジェクトはポインタによって参照される実際のオブジェクトであり、それ以上のコピーは作成されません。

は、このように複数のスレッドが同時に同じ例外ポインタ再スローである(コピーを許可されている!)、それらすべてが同じオブジェクトへの参照を持っています。

+0

これは意味があります。それでも、rethrow_exceptionの動作を「Throws:pが参照する例外オブジェクト」と記述すると、標準は混乱します。 – soulie

+0

@twicker:私はそれがかなり明確だと思います。 「例外オブジェクト」の概念は常にあり、 'std :: current_exception'はそのオブジェクトへのポインタを作成します。 –

関連する問題