copying objects in C + + is like cloning, which quickly replicates multiple identical objects with an existing object. In general, the following three scenarios will use replication for objects:
(1) Create a new object and initialize the new object with another similar existing object, for example:
Class Rect{private:int width;int height;}; Rect Rect1; Rect Rect2 (rect1); Use Rect1 to initialize the Rect2, at which point the object is copied
(2) When the function's argument is an object of the class, when this function is called with a value pass, the object's copy is also generated, for example:
void Fun1 (rect rect) {...} int main () {Rect rect1;fun1 (rect1);//The copy of the object is now return 0;}
(3) When the return value of a function is an object of a class, at the end of the function call, the object in the function needs to be copied to a temporary object and passed to the call of the function, for example:
Rect fun2 () {rect rect;return rect;} int main () {Rect rect1;rect1=fun2 ();//When Fun2 returns an object, an object copy is performed, a temporary object is copied,//and the temporary object is "assigned" to Rect1return 0;}
Object replication is done through a special constructor, which is a copy constructor (copy constructor, also called a copy constructor). The copy constructor is simple in most cases and works 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 very careful with the copy constructor. Let's take a look at the use of copy constructors.
First, the default copy constructor
Many times when we don't know the copy constructor, passing the object to a function parameter or a function return object is fine, because the compiler will give us a copy constructor automatically, which is the "Default copy constructor", which is very simple, just use "old object" The value of the data member assigns a value to the data member of the new object, which generally has the following form:
Rect::rect (const rect& r) {width = R.width;height = r.height;}
Of course, the above code is not written by us, and the compiler will automatically generate it for us. However, if you think this will solve the object replication problem, then it is wrong, let us consider the following piece of code:
Class Rect{public:rect ()//constructor, counter plus 1{count++;} ~rect ()//destructor, counter minus 1{count--;} static int GetCount () //Returns the value of the counter {return count;} Private:int width;int height;static int count;//A static member as counter};int Rect::count = 0;//Initialize counter int main () {Rect rect1;cout<& lt; " The Count of Rect: "<<rect::getcount () <<endl; Rect Rect2 (rect1); Using Rect1 to copy the Rect2, there should be two objects at this time cout<< "The Count of Rect:" <<rect::getcount () <<endl;return 0;}
This code makes a minor modification to the preceding class, adding a static member to count, counting the number of objects created, incrementing by constructors when each object is created, and decreasing by 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 understanding, at this time there should be two objects exist, but the actual program runs, the output is 1, the reaction is only 1 objects. In addition, when destroying an object, the class's destructor is called two times because it is called to destroy two objects, and the counter becomes negative. The most fundamental problem is that when copying objects, the counter is not incremented, the solution is to rewrite the copy constructor, the copy constructor is added to the counter processing, the resulting copy constructor is as follows:
Class Rect{public:rect ()//constructor, counter plus 1{count++;} Rect (const rect& R) //copy constructor {width = R.width;height = r.height;count++; Counter plus 1}~rect ()//destructor, counter minus 1{count--;} static int GetCount ()//Returns the value of the counter {return count;} Private:int width;int height;static int count;//A static member as a counter};
Writing a copy constructor yourself can be divided into two cases--shallow copy and deep copy.
Second, shallow copy
The so-called shallow copy, refers to when the object is copied, only the data members in the object is simply assigned, the above example is a shallow copy of the case, the default copy constructor is also a shallow copy of the execution. In most cases "shallow copy" has worked well, but once the object has a dynamic member, then the shallow copy will be problematic, let us consider the following code:
Class Rect{public:rect ()//constructor, p points to a space allocated in the heap {p = new int (100);} ~rect ()//destructor, releasing the dynamically allocated space {if (P! = NULL) {delete p;}} Private:int width;int Height;int *p;//A pointer member};int main () {Rect rect1; Rect Rect2 (rect1); Copy object return 0;}
A run-time error will occur before the end of this code run. The reason is that there is no proper operation for dynamically allocated content when copying objects. Let's analyze:
After running the definition Rect1 object, because there is a dynamically allocated statement in the constructor, the memory situation after execution is roughly the following:
When using Rect1 to copy rect2, because a shallow copy is performed, only the value of the member is assigned, so RECT1.P and RECT2.P have the same value at this point, that is, the two pointers point to the same space in the heap, as shown in:
Of course, this is not the result we expect, when destroying an object, the destructor for two objects will be freed two times for the same memory space, which is why the error occurred. What we need is not two P have the same value, but two P point to the space has the same value, the solution is to use "deep copy".
Third, deep copy
In the case of "deep copy", for the dynamic members of the object, you cannot simply assign a value, but should re-allocate the space dynamically, as the above example should be handled as follows:
Class Rect{public:rect ()//constructor, p points to a space allocated in the heap {p = new int (100);} Rect (const rect& r) {width = R.width;height = r.height;p = new int;//re-dynamically allocates space *p = * (R.P);} ~rect ()//destructor, releasing the dynamically allocated space {if (P! = NULL) {delete p;}} Private:int width;int Height;int *p;//a pointer member};
At this point, after the object is copied, a general picture of the memory is as follows:
Rect1 p and Rect2 p each point to a memory space at this point, but the space they point to has the same content, which is called a "deep copy."
In addition, the same problem arises with the assignment of objects that are similar to the copy of objects. This issue is discussed in the "Assignment of Objects" article.
By analyzing object replication, we find that most of the replication of objects occurs when "value passing" is performed, and there is a small trick to prevent passing by value-declaring a private copy constructor. You don't even have to define this copy constructor, because the copy constructor is private, and if the user tries to pass by value or the function returns the class object, a compilation error is obtained, which avoids passing or returning the object by value.
Deep copy and shallow copy of copy constructors in C + +--"shallow copy" and "Deep copy"