10

BクラスのインスタンスをA構築する必要があるクラスがあります。

class B
{
    B(A* a); // there is no default constructor
};

ここで、メンバーとして含まれるクラスを作成したいBので、メンバーとして追加して、のコンストラクターAに提供する必要もあります。B

class C
{
    C() : a(), b(&a) {}
    A a; // 1. initialized as a()
    B b; // 2. initialized as b(&a) - OK
};

しかし、問題は、誰かがクラス内の変数定義の順序を時々変更すると、壊れてしまうことです

class C
{
    C() : a(), b(&a) {}
    B b; // 1. initialized as b(&a) while "a" uninitialized
    A a; // too late...
};

Aクラスを変更せずにこれを解決する良い方法はありBますか? ありがとう。

4

6 に答える 6

7

クラスAとBを変更せずにこれを解決する良い方法はありますか?

コンパイラの警告をオンにします。gcc の場合、これは -Wreorder (-Wall に含まれています) です。

cc1plus: エラーとして扱われる警告
t.cpp: コンストラクター 'A::A()':
3 行目: 警告: 'A::y' は後で初期化されます
3 行目: 警告: 'int A::x'
行 2: 警告: ここで初期化された場合

または、これを検出する糸くずのようなツールを使用します。


しかし問題は、誰かがクラス内の変数定義の順序を時々変更すると…</p>

なぜ彼らはこれをするのでしょうか?何が起こるかを心配しすぎているのではないかと思います。それでも、クラスにコメントを残すことができます。

A a;  // Must be listed before member 'b'!
B b;

適切に配置されたコメントの力を過小評価しないでください。:) 次に、故意にそれらを無視する人が、それに値するものを取得できるようにします。結局のところ、あなたは C++ を使用しています。

于 2011-02-15T21:25:39.527 に答える
5

この問題を解決するには、Base-from-Memberと呼ばれるよく知られた C++ のイディオムを使用します。

基本クラスを次のように定義します。

class C_Base
{
    A a; //moved `A a` to the base class!
    C_Base() : a() {}
};

class C : public C_Base
{
    C() : b(&a) {}
    B b; // 1. initialized as b(&a) while "a" uninitialized
    //A a; // too late...
};

現在、aは の前に初期化されることが保証されていますb

于 2011-02-15T21:18:18.267 に答える
2

b を unique_ptr に格納し、初期化リストではなく本体に設定します。

class C
{
    C() :a() {
        b = std::unique_ptr<B>(new B(&a));
    }
    A a;
    std::unique_ptr<B> b;
};
于 2011-02-15T21:30:02.390 に答える
0

1 つのオプションは、A を明示的に格納するのではなく、代わりに動的割り当てを使用して新しい A を作成し、B に格納することです。

class C {
public:
       C() : b(new A) {
           // handled in initialization list
       }
private:
       B b;
};

これにより、A が B より前に作成されることが保証されるため、この問題が発生するのを防ぐことができます。

于 2011-02-15T21:14:05.180 に答える
0

問題は、3 番目の例で自分の足を撃っていることです。C++ では、クラス/構造体のメンバー変数の順序が重要です。特定の問題をどのように解決しようとしても、クラスの設計/メンバーのレイアウトが不十分なために初期化されていないデータをコンストラクターに渡すと、コードの種類によっては、初期化されていないデータを操作することになり、未定義の動作が発生する可能性があります。

あなたの特定の例に対処するために、 がB本当に必要でAあり、関係が 1 対 1 である場合、オブジェクトとオブジェクトのAB両方を正しい順序で持つ新しいクラスを作成し、 to のアドレスを渡してみませんか。あれは:ABAB

class AB
{
public:
  AB():b_(&a_) {}

private:
  A a_;
  B b_;
};

クラスは、 andの代わりにC使用することで、順序付けの問題を回避できるようになりました。ABAB

class C
{
public:
  ...
private:
  AB ab_;
};

前述のように、これはもちろん と の間の 1:1 の関係を前提AとしていBます。Aオブジェクトを多くのオブジェクトで共有できる場合B、事態はさらに複雑になります。

于 2011-02-15T21:14:21.360 に答える
0

Cの実装と構造をどの程度制御できるかわかりませんが、クラスCでオブジェクト自体を使用する必要がありますか? 代わりにポインターを使用するようにクラスを再定義してから、初期化リストからそれらを移動できますか?

class C
{
   C()
   {
     a = new A;
     b = new B(a);
   }
   ~C() {delete a; delete b;}

   A* a;
   B* b;
};

これにより、宣言の順序の問題は回避されますが、宣言が正しく作成されていることを確認するという新しい問題が生じます。また、大量の C を頻繁に作成する場合は、初期化リストの方がわずかに高速です。

于 2011-02-15T21:30:36.073 に答える