4

次のクラスがあります。

class A
{
public:
    A() { x = 0; std::cout<<"A default ctor()\n"; }
    A(int x_) { x = x_; std::cout<<"A normal ctor()\n"; }
    int x;
};

class B
{
public:
    B() { std::cout<<"B ctor()\n"; }
private:
std::string str;
};

そして、オブジェクト A をパラメーターとして取り、オブジェクト B を作成する関数:

B
createB(const A& a) {
    std::cout<<"a int: "<<a.x<<"\n";
    return B();
}

タイプ A と B のメンバーを持ち、A オブジェクトを作成する前に B オブジェクトを作成するクラス C を設計すると、A オブジェクトを使用してそのようにすると、警告なしでコンパイルされますが、暗黙のうちにバグが発生します。

class C
{
public:
    C(): b(createB(a)), a(10) {}
private:
    B b;
    A a;
};


int main()
{
    C c;
    return 0;
}

もちろん、上記の例は些細な例ですが、実際にはもっと複雑なコードで見たことがあります (金曜日の午後 8 時 30 分で、segfault につながるこのバグを修正したところです)。

どうすればこれを防ぐことができますか?

4

2 に答える 2

2

他の人が提案したこと、つまり、オブジェクトが使用前に初期化されるようにする責任は設計者にあるということに同意します。あなたの場合、それを行う2つの方法があります。

最初に (そして最も簡単に)、クラス定義のaとの順序を逆にします。b

class C
{
public:
    C(): b(createB(a)), a(10) {}
private:
    A a;
    B b;
};

第二に、他のメンバーの初期化の前に初期化が行われることを本当にa強調したい場合は、基本クラスに移動できます。

class CBase
{
protected:
    CBase(): a(10) {}
protected:
    A a;
};

class C : private CBase
{
public:
    C(): b(createB(a)) {}
private:
    B b;
};
于 2012-10-26T18:05:50.103 に答える
0

私は3つの可能な選択肢を見ます:

A構築する前に構築する必要がありますC

class C
{
public:
   C(const A& a) : a_(a), b_(a) {}
private:
   A a_;
   B b_;
};

A'B'を構築する前に構築します。

Bまでの構築を遅らせることAは完了です。これにより、未定義の動作が発生しなくなりますが、インターフェイスを介した適切な動作は強制されません(オプション1および3のように

class C
{
public:
   C() : a_(/* construct as appropriate */)
   {
      b_.reset(new B(a_));
   }

private:
   A a_;
   std::unique_ptr<B> b_;
};

デザインで許可されている場合は、B含む(および公開する)必要がありますA

これは些細な例からは可能であるように見えますが、実際にはそうではない場合があります。

class B
{
public:
   const A& my_a() {return a_;}
private:
   // construct as appropriate (?)
   A a_;
};

class C
{
private:
   B b_;
};
于 2012-10-26T17:35:42.187 に答える