2017-04-25 12 views
3

ローカル静的オブジェクトのコンストラクタからスローされた例外をどのように扱うべきですか?例えば、私は、次のコードた:私は理解するようローカル静的オブジェクトと例外

class A 
{ 
public: 
    A() {throw runtime_error("Ooops");} 
}; 

void foo() 
{ 
    static A a = A(); 
    cout << "Continue" << endl; 
} 

int main(void) 
{ 
    try 
    { 
     foo(); 
    } 
    catch(...) 
    { 
    } 
    foo(); // Prints continue 
    return 0; 
} 

を、第二fooメソッドを呼び出した場合には、オブジェクトaは完全に構築されたオブジェクトとして扱われ、コンストラクタが呼び出されません。 (それ以上の場合は、aのデストラクタのように見えます)

+3

いいえ、ご理解いただけません。あなたはこれを自明に試すことができました(https://wandbox.org/permlink/0zqV3BglWpVZSgRM)。 –

+0

例外をスローし、コンストラクタの実行を終了した場合(オブジェクトの構築を完了しなかった場合)、 'a'が完全に構築されることをどのように期待しますか? – Rogus

+0

'static A a = A();'なぜこれをやったのですか?なぜコピーを初期化するのですか? –

答えて

4

これが本当であれば、これはコンパイラのバグです。

(ただし、VTT claims that this code produces the expected result with Visual Studio 2015、私はダブルチェックあなたの結果をお勧めします。)

ここでは、標準義務付け行動です:

[C++14: 6.7/4]:ゼロ初期化(8.5)すべてのブロックのその他の初期化が行われる前に、静的記憶領域(3.7.1)またはスレッド記憶領域(3.7.2)の-scope変数が実行されます。ブロックが最初に入力される前に、静的記憶期間を持つブロックスコープエンティティの定数初期化(3.6.2)が実行されます(該当する場合)。インプリメンテーションが静的または静的にネームスペーススコープ(3.6.2)内の静的またはスレッド記憶期間を持つ変数を初期化するのと同じ条件の下で、スレッド記憶期間がスタティックまたは の他のブロックスコープ変数の早期初期化を実行することができます。それ以外の場合、そのような変数は、最初のコントロールがその宣言を通過すると初期化されます。そのような変数は、その初期化の完了時に初期化されたものと見なされます。 例外がスローされて初期化が終了した場合、初期化は完了していないため、次回制御が宣言に入るときに再試行されます。変数が初期化されているときにコントロールが同時に宣言に入ると、並行実行は初期化の完了を待機します。変数が初期化されている間にコントロールが宣言を再帰的に再入力すると、その動作は未定義です。 [..]

GCC 6.3.0 correctly attempts to reconstruct the A(したがって再びスロー)。


もっと上が、それは

ませんと呼ばれていないため、最初の例外投げのデストラクタのように思える、それができなくなります。最初に正常に作成されたことのないオブジェクトを破棄することはできません。

[C++14: 15.2/2]:初期化または破壊例外によって終了されるデストラクタは(ユニオン状のクラスの変異体を除く)は完全に構築サブオブジェクトの全てに対して実行されたであろう任意の保存期間のオブジェクト、つまりため、あります主要コンストラクタ(12.6.2)が実行を完了し、デストラクタがまだ実行を開始していないサブオブジェクト。同様に、オブジェクトの委任されていないコンストラクタが実行を完了し、そのオブジェクトの委譲コンストラクタが例外で終了した場合、オブジェクトのデストラクタが呼び出されます。オブジェクトがnew-expressionに割り当てられていた場合、一致する解放機能(3.7.4.2,5.3.4,12.5)があればそれが呼び出され、オブジェクトが占有する記憶域が解放されます。ところで


、これは問題が解決しない、あなただけ書く必要があります。

static A a; 

、一時からコピー初期設定は無意味です。

+1

6.7/4 "例外をスローすることによって初期化が終了した場合、初期化は完了していないので、次回制御が宣言に入るときに再試行されます。 – aschepler

+0

@aschepler:ありがとう –

+0

@BoundaryImposition、接続された/ dettachedデバッガのプログラムの動作が異なります(私はmsvc 2015を意味します)。 dettachedデバッガプログラムが失敗した場合 – LmTinyToon

2

静的ローカル変数の各インスタンスも、静的変数の作成後にtrueに設定されるグローバルブール変数を暗黙的に作成します。コンストラクタが次回のメソッド呼び出しよりもスローされた場合、静的変数を構築する別の試みがあります。

+0

ええ、しかしOPはそうではないことを示しました。 –

+0

ええと、彼は彼のコードを実行していないように見えます(実際には予知されない例外があります)。[作業例](http://ideone.com/4HZSTO)を参照してください。VS2015でもうまく動作します – VTT

+0

面白い!確認するVS2015はありません。 –

関連する問題