2

初心者の C++ プログラマーです。ネストされたクラス Inner を持つクラス Outer があるとします。Inner には、構築中に設定された Outer へのポインター メンバーが含まれています。Outer には、それ自体を指す新しい Inner を作成し、それをベクトルに追加する関数 AddNewInner() が含まれています。

class Outer {

public:

    class Inner {
    public:
        Inner(Outer* outerParent) : mOuterParent(outerParent) {}
        Outer* mOuterParent;
    }

    void AddNewInner() {
        Inner newInner(this);
        mInnersVec.push_back(newInner);
    }

    vector<Inner> mInnersVec;
}

Outer の新しいインスタンスを作成し、AddNewInner() を呼び出して Inners をベクターに追加する場合、これは正常に機能します。ただし、Outer のインスタンスのコピーを作成しようとすると、問題が発生しました。Outer コピーの Inner のベクトルは、コピー (それ自体) を指さず、元の Outer を指しています。

Outer outerA;
outerA.AddNewInner(); 
Outer* ptrA = outerA.mInnersVec[0].mOuterParent; // this points to outerA, good!

Outer outerB = outerA;
Outer* ptrB = outerB.mInnersVec[0].mOuterParent; // this still points to outerA, bad!

オリジナルではなくコピーを指すには、コピー内のインナーのベクトルが必要です。これを達成するための最良の方法は何ですか、またはおそらく同じことを行う別の方法はありますか?

4

2 に答える 2

2

正しい、これは予想される動作です。C++ でオブジェクトのコピーを作成する場合、コンパイラはコピー コンストラクターを使用します。クラスに対して独自のコピー コンストラクターを作成していない場合は、コンパイラによって生成されたコピー コンストラクターが使用されます。このコピー コンストラクターは、各メンバーに対して (おそらく生成された) コピー コンストラクターを順番に実行します。

したがって、 をコピーするOuterと、一連のイベントは次のようになります。

  • コンパイラは、(生成された) コピー コンストラクタを実行します。Outer
  • これにより、 のコピー コンストラクターが実行されstd::vectorます。このコンストラクターは、新しいベクターのストレージを割り当ててから、各要素のコピー コンストラクターを順番に実行します。
  • したがって、(生成された) コピー コンストラクターはInner各要素に対して実行され、メンバー ポインターをコピーするだけです (まだ元の を指していますOuter)。

Innerをコピーするときに要素を更新するには、必要に応じてポインターを更新Outerするカスタム コピー コンストラクターを作成する必要があります。Outerそのようなもの:

Outer::Outer(const Outer& other)
    : mInnersVec(other.mInnersVec) // Do initial vector copy
{
    // Update vector elements
    for (auto& elem : mInnersVec) {
       elem.mOuterParent = this;
    }
}

カスタム コピー コンストラクターを記述するときは常に、カスタム代入演算子も記述する必要があることに注意してください。お気に入りの C++ 教科書でコピーと代入について読むことをお勧めします :-)。

于 2016-07-25T05:23:54.080 に答える
1

クラスのカスタムコピー コンストラクター/代入演算子を使用する必要があります。Outer* mOuterParentこれにより、変数のディープ コピーを作成できます。おそらく新しいものを作成します。

ポインターをコピーすると、メモリ内の特定のアドレス空間を指す変数がコピーされます。ポインタをコピーしても、2 つの「アクセサ変数」を介して同じ「真の変数」にアクセスできるようになるだけです。

あなたの例では、特定のオブジェクトの変数Outer* mOuterParentは、その特定のオブジェクトのコピーをいくつ作成しても、そのポインターが指すクラスの同じインスタンス化を常に指します。outerouter

于 2016-07-25T05:17:23.367 に答える