メモの日々


2007年06月05日(火) [長年日記]

  • 久〜しぶりにスーツを着た。相変わらずズボンきつきつ。なんとかせねば。

[c++] コンストラクタ内で例外がthrowされたときのメンバの破棄処理

class X {
public:
    X();
    ~X();
private:
    A a;
    B b;
};

というクラスのコンストラクタX()内でメンバaの初期化に成功した後メンバbの初期化中に例外が発生したらメンバaのデストラクタは呼び出されるのか、というのがよく分からなかったのでメモ。

C++ FAQのFAQ 26.06に、aのデストラクタはちゃんと呼び出される旨書かれていた。そこに載っていた例と同じようなコードで試して、確かに呼び出されていることを確認した。コードもメモ。

#include <iostream>
#include <stdexcept>

using std::cout;
using std::endl;

class A {
public:
    A() {cout << "A constructor" << endl;}
    ~A() {cout << "A destructor" << endl;}
};

class B {
public:
    B() {
        cout << "B throw runtime_error" << endl;
        throw std::runtime_error("in B");
    }
    ~B() {cout << "B destructor" << endl;}
};

class X {
public:
    X() : a(), b() {cout << "X constructor" << endl;}
    ~X() {cout << "X destructor" << endl;}
private:
    A a;
    B b;
};

int main() {
    try {
        X x;
    } catch (std::runtime_error e) {
        cout << "caught: " << e.what() << std::endl;
    }
}

実行結果は

A constructor
B throw runtime_error
A destructor
caught: in B

となり、Aのデストラクタは呼び出されている。ただし、main内でXのインスタンス生成処理をtryで囲まないと

A constructor
B throw runtime_error
terminate called after throwing an instance of 'std::runtime_error'
  what():  in B
アボートしました (core dumped)

となり、Aのデストラクタ呼び出しのメッセージは出力されない。

プログラミング言語C++第3版内からその旨書いてあるページを見つけようとしたけど見つけられず。C++ランゲージ クイックリファレンスには、「6.3.4 コンストラクタ」節に

初期化中に例外が送出された場合は、生成が完了しているオブジェクトのデストラクタだけが呼び出される。

と説明があった。

やること

  • 年金