2016-03-29 3 views
6

http://ideone.com/UtVzxwてみキャッチシンタックスコンストラクタ

struct base 
{ 
    base() { throw std::exception(); } 
}; 

struct derived : public base 
{ 
    derived() try : base() { } 

    catch (std::exception& e) 
    { 
     std::cout << "exception handled" << std::endl; 
    } 
}; 

int main() 
{ 
    derived a; // My app crashes. 
    return 0; 
} 

は私のアプリの書き込み "の例外が処理さ" と実行を継続Shoun't?

私が見つけた唯一の解決策は、 "a"の構成をtry/catchブロックで囲むことです。しかし、もし私がそうしたら、最初にコンストラクタにtry/catchを持つのは何ですか?私は多分それが割り当てられているかもしれないメンバー変数をクリーンアップすることです使用していると思いますか? デストラクタが呼び出されていないためですか?

以下は動作しますが、例外を2回処理します。

struct base 
{ 
    base() { throw std::exception(); } 
}; 

struct derived : public base 
{ 
    derived() try : base() { } 

    catch(std::exception& e) 
    { 
     std::cout << "exception 1" << std::endl; 
    } 
}; 

int main() 
{ 
    // This works fine. 
    try { 
     derived a; 
    } 
    catch(std::exception& e) 
    { 
     std::cout << "exception 2" << std::endl; 
    } 
    return 0; 
} 

私はちょうど私が単にコンストラクタのtry/catch構文をかわすと、これを書いてはならない理由を自問しようとしている:

スーパークラスのコンストラクタ周りのtry/catchをラッピング
struct base 
{ 
    base() { throw std::exception(); } 
}; 

struct derived : public base 
{ 
    derived() : base() { } 
}; 

int main() 
{ 
    // This works fine. 
    try { 
     derived a; 
    } 
    catch(std::exception& e) 
    { 
     std::cout << "exception handled" << std::endl; 
    } 
    return 0; 
} 

答えて

7

コンストラクタのfunction-try-blockは、例外がスローされることを防ぎません。ここではC++標準のドラフトN4140からの抜粋は、[except.handle]、です:return文は、コンストラクタの機能してみてください - ブロックのハンドラに表示された場合

14、プログラムは病気-形成されています。

15現在処理されている例外は、コンストラクタまたはデストラクタのファンクションtryブロックのハンドラの終了に達した場合に再提供されます。そうでない場合、...

理由は、基本クラスまたはメンバーコンストラクタが例外をスローすると、オブジェクト全体の構築が失敗し、修正する方法がないため例外がありますスローされる。

はこの上GOTWをあります、とbottomlineは

コンストラクタ関数トライブロックハンドラは一つだけの目的を持っている - 例外を翻訳します。 (そしておそらくロギングやその他の副作用をすることもあります)。他の目的には役に立たない。

はい、最後のコードサンプルは完璧です。

+0

Googleでは、例外を使用しないというポリシーがあり、クールなライブラリを見つけましたが、コンストラクタでのみスローされたクラスを継承したいクラスは他にはありません。それを継承する場合は、派生クラスを使用するすべての人が毎回try/catchを使用する必要があります。あなたはその場合何をしますか?唯一の答えは次のようなものです:コンストラクタのために別のライブラリを使用してください。 – James

+0

@Phantomまたはそれを継承しないで、そのメンバーへのポインタを作成し、コンストラクタ本体で初期化します。しかし、私はGoogleであなたがそのライブラリを使用することを許可しないと信じています。 –

3

スーパークラスのコンストラクタにスローされる例外をトラップできます。 catchブロックが終了すると、例外は自動的に再スローされ、例外は引き続き伝播します。結局のところ、スーパークラスは構築されませんでした。それは例外を投げた。だから、実際には、サブクラスのコンストラクタで気楽に続けてはいけません。そして、構築されたサブクラスで終わることはできませんが、スーパークラスは構築されませんでした。それは意味をなさない。

http://en.cppreference.com/w/cpp/language/function-try-blockから:

機能してみてくださいブロックの主な目的は、ログインしたり、変更、および が、その後 コンストラクタのメンバ初期化子リストからスローされた例外を再スローすることです。それらはデストラクタや通常の関数 でほとんど使用されません。

これは実際にはfunction-tryブロックの第一の付加価値です。これは、「この関数は例外を投げました」というログを記録する便利な場所であり、関数全体、この種類の通常の例外処理に影響を与えることはありません。

関連する問題