2

Novice C++ programmer here. Let's say I have a class Outer with a nested class Inner. Inner contains a pointer member, set during construction, to Outer. Outer contains a function AddNewInner() that creates a new Inner pointing to itself and adds it to a vector.

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;
}

This works fine when creating a new instance of Outer and calling AddNewInner() to add Inners to the vector. However, I have run into an issue when I try to create a copy of an instance of Outer: The Outer copy's vector of Inners do not point to the copy (itself), they still point to the original 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!

I need the vector of Inners in the copy to point to the copy, not the original. What's the best way of accomplishing this, or perhaps is there an alternate way to do the same thing?

4

2 回答 2

2

Correct, this is expected behaviour. When you create a copy of an object in C++, the compiler uses the copy constructor. If you haven't written your own copy constructor for a class, then it uses the compiler-generated copy constructor, which simply runs the (possibly generated) copy constructor for each member in turn.

So when copying an Outer, the sequence of events goes like this:

  • Compiler runs the (generated) copy constructor for Outer
  • This runs the copy constructor for std::vector. This constructor assigns the storage for the new vector, and then runs the copy constructor for each element in turn
  • So the (generated) copy constructor for Inner runs for each element, which just copies the member pointer (still pointing to the original Outer).

In order to update the Inner elements when copying an Outer, you need to write a custom copy constructor for Outer which updates the pointers as you'd like. Something like so:

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

Note that whenever you write a custom copy constructor, you almost always need to write a custom assignment operator too. I'd recommend reading up on copying and assignment in your favourite C++ textbook :-).

于 2016-07-25T05:23:54.080 回答
1

You need to utilize a custom copy constructor/assignment operator for your class. This will allow you to make a deep copy of your Outer* mOuterParent variable; probably creating a new one.

When you copy a pointer, you are copying a variable which points to a specific address space in memory. Copying the pointer only gives you the ability to access the same 'true variable' through two 'accessor variables'.

In your example the Outer* mOuterParent variable of a particular outer object will always point to the same instantiation of an outer class pointed to by that pointer no matter how many copies of that particular object you make.

于 2016-07-25T05:17:23.367 回答