"Shallow copy" and "Deep copy"

Source: Internet
Author: User
Tags shallow copy

The replication of objects in C + + is like "cloning", with an existing object quickly copying multiple identical objects. In general, replication of objects is used in three of the following situations:

(1) Create a new object and initialize the new object with an existing object of another class, for example:

[CPP] view Plain copy class Rect {private:int width;   int height;      };   Rect Rect1;  Rect Rect2 (RECT1); Initializes the rect2 using Rect1, where the object is replicated

(2) When the function's argument is an object of the class, this function is invoked with value passing, which also results in the replication of the object, for example:

[CPP] view plain copy void Fun1 (Rect Rect) {...}       int main () {Rect rect1;    FUN1 (RECT1);   The object is copied return 0; }

(3) When the return value of a function is an object of a class, at the end of a function call, the object in the function is required to copy a temporary object and pass it to the call where the function is modified, for example:

[CPP] view plain copy Rect fun2 () {Rect Rect;   return rect;       int main () {Rect rect1;          Rect1=fun2 ();   When Fun2 returns an object, it performs an object copy, duplicates a temporary object,//and assigns the temporary object "assignment" to rect1 return 0; }

The replication of objects is done through a special constructor, which is the copy constructor (copy constructor, also called the copy constructor). Copy constructors are simple in most cases and can work well even when we don't know it exists, but in special cases, especially when there are dynamic members in the object, we need to be particularly careful with copy constructors. Now let's take a look at the use of copy constructors.

One, default copy constructor

Most of the time, when we don't even know the copy constructor, passing objects to function arguments or function return objects can be done well because the compiler will automatically generate a copy constructor for us, which is "default copy constructor", which is simple enough to use "old objects" only The value of the data member is assigned to the data member of the new object, which generally has the following form:

[CPP] view plain copy rect::rect (const rect& r) {width = r.width;   Height = r.height; }

Of course, the above code does not need us to write, the compiler will automatically generate for us. But if you think this solves the problem of replication of objects, that's wrong, let's consider the following code:[CPP]  View plain copy class rect   {   public:       rect ()       //  constructors, counters plus 1       {            count++;       }        ~rect ()      //  destructor, counter minus 1       {            count--;       }        static int getcount ()        / /  return counter value        {            return count;       }   private:        int width;       int height;        static int count;       //  a static member as counter   };      int rect::count = 0;        //  Initialization counters       int main ()    {       Rect rect1;        cout<< "the count of rect: " <<rect::getcount () <<endl;       rect rect2 (rect1);   //  Using Rect1 to replicate rect2, there should be two objects        cout<< the count of rect:   "<<rect::getcount () <<endl;       return 0;  }   

This code makes a small change to the previous class, adding a static member to count the number of objects created, incrementing by the constructor when each object is created, and descending through the destructor when destroying the object. In the main function, first create the object rect1, output the number of objects at this time, and then use Rect1 to copy the object Rect2, and then output the number of objects at this time, according to understand, there should be two objects exist, but the actual program running, the output is 1, reflecting only 1 objects. In addition, when the object is destroyed, the class's destructor is called two times because the destroyed two objects are called, and the counter becomes negative. These problems occur most fundamentally in the replication of objects, the counter is not incremented, the solution is to rewrite the copy constructor, in the copy constructor added to the counter processing, the form of the copy constructor as follows:[CPP]  View plain copy class rect   {   public:       rect ()       //  constructors, counters plus 1       {            count++;       }        rect (const rect& r)    //  copy Constructors         {           width = r.width;            height = r.height;            count++;          //   Counter plus 1       }       ~rect ()       //  destructor, counter minus 1       {            count--;       }       static int  GetCount ()    //  return counter value        {            return count;       }   Private:        int width;       int height;        static int count;       //  A static member as counter   };  

Writing your own copy constructor can be divided into two situations--a shallow copy and a deep copy.

Second, shallow copy

A shallow copy refers to a simple assignment of a data member in an object when the object is copied, and the example above is a shallow copy.The default copy constructor also performs a shallow copy。 In most cases, "shallow copy" is already working well, but once the object has a dynamic member, then the shallow copy will go wrong, let's consider the following code:[CPP]  View plain copy class rect   {   public:       rect ()       //  Constructor, p pointing to a space allocated in the heap        {           p = new int (;  )      }       ~rect ()      //  destructor functions, releasing dynamically allocated space         {           if (p !=  NULL)               {                delete p;            }       }   private:        int width;       int height;      & Nbsp;int *p;     //  A pointer member   };      Int main ()    {       Rect rect1;       rect  rect2 (RECT1);   //  replication Objects        return 0;   }  

A run error occurs before this code is run. The reason is that when the object is replicated, the dynamically allocated content is not properly manipulated. Let's analyze:

After you run the definition Rect1 object, because there is a dynamically allocated statement in the constructor, the memory situation after execution is roughly as follows:

When using Rect1 to copy rect2, because a shallow copy is performed, only the values of the members are assigned, so RECT1.P and RECT2.P have the same value, i.e. the two pointers point to the same space in the heap, as shown in the following illustration:

Of course, this is not the result we expected, and when the object was destroyed, the destructor of two objects would be released two times for the same memory space, which is why the error occurred. What we need is not two p having the same value, but two P pointing to a space that has the same value, the solution is to use "deep copy".

Third, deep copy

In the case of "deep copy", for dynamic members in an object, it is not possible to simply assign a value, but to dynamically allocate space, as the example above should be handled as follows:

[CPP]  View plain copy class rect   {   public:       rect ()       //  Constructor, p pointing to a space allocated in the heap        {           p = new int (;  )      }       rect (const rect& r)         {           width = r.width;           height = r.height;            p = new int;    //  re-allocate space for new objects             *p = * (R.P);        }       ~rect ()      //  destructor functions, releasing dynamically allocated space     &NBSP;&NBSp;  {           if (P != NULL)                {                delete p;            }       }   private:       int  width;       int height;       int *p;      //  A pointer member   };  

At this point, after the object is replicated, an approximate memory is as follows:

At this point P and Rect2 p of rect1 each point to a section of memory space, but they point to the space has the same content, this is called "deep copy".

In addition, the same problem occurs in the case of an assignment of objects that is similar to the copy of an object. Discuss this issue again in the "Assignment of Objects" article.

By analyzing the replication of objects, we find that most of the object's replication occurs when the value is passed, and there is a trick to prevent passing by value-declaring a private copy constructor. You don't even have to define this copy constructor, so because the copy constructor is private, if the user tries to pass by value or returns the class object, a compilation error is obtained, which avoids passing or returning the object by value.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.