Friday, April 15, 2011

Deep copying a vector c++

Read the Game Dev Forum
Read the Solution
Read the Conclusion


The Problem

Recently I came across a problem when copying vectors in c++. So I say something like this:

clone_vector = original_vector;

Where the orignal_vector is a vector of pointers to objects, all of which have a common base class and also a string stream as a private member. A simplified version of the objects held in the vector is as follows:


class Digit
{
        protected:
                //x and y positons
                int Xpos;
                int Ypos;
  
                //value in string format
                std::stringstream svalue;
        
  public:
        Digit();
        
};


class Realnum: public Digit
{
protected:
        float value;
public:
        Realnum( int  x, int y);

};


The problem with the copy statement is that this is what is called "shallow copying". Shallow copying does not dereference pointers, in other words pointers in the clone_vector point to the address of pointers in the original_vector. So if you change a value in the orignal_vector you will automatically change a value in the clone_vector and vice versa. A good picture and explanation of deep vs shallow copy can be found at the wikipedia page . I want to be able to create a clone copy of my vector that I can manipulate without manipulating the original and vice versa.


Solution


To deep copy a vector composed of objects in a derived class that also contain a string stream member (trust me that's imposing a lot of conditions, if you can copy this you can copy anything) you need to do the following.

1. Create a copy constructor such that each time an object is created in the clone vector it has it is deferenced
(a copy constructor is a constructor that takes a previously existing instance and make a copy of it. Read about it here)

2. create a desctructor

3. create a clone function to properly create a copy

4. Implement a copying process to create clones of vectors

So Here is what The class now looks like:

class Digit
{
        protected:
                //x and y positons
                int Xpos;
                int Ypos;
  
                //value in string format
                std::stringstream svalue;
        
  public:
        Digit();
        Digit(const Digit &copy)
{
Xpos = copy.Xpos;
Ypos = copy.Ypos;

svalue << copy.svalue.str();
}

        ~Digit();

//copy fucntion
                virtual Digit* clone() const
        { return new Digit( *this ); }

};


class Realnum: public Digit
{
protected:
        float value;
public:
        Realnum( int  x, int y);
        Realnum(const Realnum &copy): Digit(copy)
        {
value = copy.value;
}
        ~Realnum();

//copy fucntion
Realnum* clone() const
        {return new Realnum( *this);}
};


Notice that the derived class has a copy constructor which gives argument to the super classes copy constructor and that each copy constructor assigns every private member (variables of the object) a value. That what needs to be done if you want to use polymorphism when copying. Also notice that the clone function is virtual in the base class. That is because it is better to define a clone function for each subclass. Now copy using this technique:

//resize the clone vector
  clone_vector.resize(original_vector.size());

  for(int i=0; i< original_vector.size(); i++)
  {
   clone_vector[i] = original_vector[i]->clone();
  }
each element of the vector is properly cloned using deep copy. Voila!

Conclusion

There are most likely other techniques to cloning vectors this is just one of them. Also this is a simplified example I used in order to post the question on the gamedev forum. The real classes contain lots of members including pointers and 2 other derived classes. For a clear reference to this problem review the code in "aside 14 math game".

1 comment:

  1. An object copy is a process where a data object has its attributes copied to another object of the same data type. In .Net Shallow copy and deep copy are used for copying data between objects....more.

    ReplyDelete