Brief analysis of "C + +" depth copy

Source: Internet
Author: User

The problem of deep copy and shallow copy in C + + is a point of knowledge that deserves our attention, and if you don't pay attention in programming, you may be negligent and cause a bug. This article tells you a lot about C + + shades.

We know that for general objects:

int a = 1; int b = 2;

Such assignments, which are simple to copy, are not typical for class objects, because they contain various types of member variables, and problems occur during the copy process.

For example:

#include  <iostream>using namespace std;class String{public:     String (char str =  "")         :_str (New char[strlen (str)  + 1])  // +1 is to avoid an empty string causing an error     {         strcpy (_STR&NBSP;,&NBSP;STR);    }         //  Shallow copy     string (const string& s)          :_str (S._STR)     {}         ~string ()     {        if (_STR)          {             delete[] _str;            _str =  null;        }        cout<< "~String ()" <<endl;     }        void display ()      {        cout<<_str<<endl;    }     private:    char *_str;}; Void test () {    string s1 ("Hello");     string s2 (S1);     string.display ();     }int main () {    Test ();         return 0;}

Operation Result:

650) this.width=650; "src=" Http://s3.51cto.com/wyfs02/M00/7D/88/wKiom1bqRJ7CC1j7AABxvgeu1pI402.png "title=" capture. PNG "alt=" Wkiom1bqrj7cc1j7aabxvgeu1pi402.png "/>

We found that the compilation passed, but crashed = =ll, which is the problem with the shallow copy.


The fact is that, in the object copy process, if there is no custom copy constructor, the system provides a default copy constructor, the default copy constructor for the base type of the member variable, in bytes, for the class type member variable, the corresponding type of the copy constructor. The prototype is as follows:

String (const string& s) {}

However, the default functions provided by the compiler are not perfect.


The default copy constructor is copied in bytes during the copy process, and for pointer-type member variables, only the pointer itself is copied, not the target that the pointer points to-a shallow copy.


Visualize with diagrams as:


650) this.width=650; "src=" Http://s1.51cto.com/wyfs02/M01/7D/86/wKioL1bqSOax7GQiAAAb-81vW_4778.png "title=" 2MMS297{NN]{UMR) w8no4a8.png "alt=" Wkiol1bqsoax7gqiaaab-81vw_4778.png "/>

After the object is copied, in fact the member pointer _str in S1 and S2 point to a memory space (that is, the memory space is shared), when the S1 destructor, delete the member pointer _str point to the memory space, The same memory space appears as "Double Free", which makes an error when the S2 is destroyed by the same point (which is now turned into a wild pointer) and to release the memory space that has been freed by the S1 destructor. A shallow copy still has a problem because a space is shared by two different sub-objects, so long as one of the sub-objects changes the value, the value of the other object changes as well. So this is not the result we want, the colleague is not the true meaning of replication.


To solve the shallow copy problem, we draw a deep copy, the custom copy constructor, as follows:

String (const string& s): _str (New Char[strlen (S._STR) + 1]) {strcpy (_str, S._STR); }

It's no problem running.


So, is there any other place in the program that uses copy constructors?

Answer: The copy constructor is used when the function has an object-type parameter (that is, a copy construct) or the return value of the object type (the return value when the value is assigned).


The copy assignment is basically the same as copy copy. Just copy assignment is an operator overload problem. For example, if the main function is: String S3; s3 = S2; This allows the system to invoke the default copy assignment function provided by the system at execution time, with the following prototype:


void operator = (const string& s) {}

Our custom assignment functions are as follows:

void operator= (const string& s) {if (_str! = s._str) {strcpy (_STR,S._STR);   } return *this; }


But this is just a beginner's level of writing, with too few questions to consider. We know that for normal variables a=b returns a reference to Lvalue a, so it can continue to receive other values (a=b) = 30 as an lvalue, so that our operator overloads return a reference to the class object (otherwise the return value will not be evaluated as an lvalue), as follows:

string& operator= (const string& s) {if (_str! = s._str) {strcpy (_STR,S._STR);    } return *this; }


And the above is actually problematic, because when executing the statement, _STR has been constructed to allocate memory space, but so the pointer assignment, _STR directly to another new out of memory space, and discarded the original memory, which caused a memory leak. Should be changed to:

string& operator= (const string& s) {if (_str! = s._str) {delete[] _str;            _str = new Char[strlen (S._STR) + 1];        strcpy (_STR,S._STR);    } return *this; }

At the same time, also take into account the circumstances of their own assignment.


  But is it perfect to write like this? Do you want to think about it again, there are problems?! In fact, I can tell you, such a writing is at most a junior engineer's writing. As mentioned earlier, in order to ensure that the memory does not leak, we delete[]  _str before we put new out of space to _str, but the problem is that you have considered , so obviously this kind of writing still has the problem. General Senior Engineer's writing will be like this:

string& operator= (const string& s) {if (_str! = s._str) {Char *tmp = new Char[strlen (            S._STR) + 1];            strcpy (TMP, S._STR);            Delete[] _STR;        _STR = tmp;    } return *this; }

This is a more comprehensive writing.


But!!! And the more simple copy construction and assignment functions written by the Elder master, we see fast:

< veteran copy constructors >

String (const string& s): _str (NULL) {String tmp = S._STR;    Swap (_STR, TMP._STR); }

< Elder-level assignment functions >

1. string& operator= (const string& s) {if (_str!       = s._str) {String tmp = S._STR;     Swap (_STR, TMP._STR);   } return *this;    }//2. string& operator= (string& s)//This will copy constructs a temporary object s {if (_str! = s._str) {swap (_str, S._STR);//Swap this-   >_str and temporarily generated object data members S._str, leaving the scope automatically destructors release} return *this; }

Do you see the clues?


In fact, this is with the help of the custom copy constructor above. Defines a local object, TMP, which has allocated a chunk of memory for the TMP member pointer in the copy construct, so you simply need to swap the TMP._STR with THIS->_STR to simplify the design of the program, because TMP is a local object, leaving the scope calls the destructor to release the interchange to TMP._STR memory to avoid memory leaks.

This is very worthy of our study and reference.


This is my understanding of C + + depth copy, if there is a mistake, welcome message ^_^


Note Overall code:

#include  <iostream>using namespace std;class String{public:     String (char *str =  "")         :_str (new char[ strlen (str)  + 1])     {        strcpy (_ STR&NBSP;,&NBSP;STR);    }        //  Shallow copy     string (Const string& s)         : _str (S._STR)     {}    //assignment operator overload     //a problem that can cause a memory leak ...     string& operator= (const string& s)     {         if (_STR&NBSP;!=&NBSP;S._STR)          {            strcpy (_STR,S._STR) ;         }        return *this;     }    //  deep copy   < traditional notation >    string (const string & s)         :_str (New char[strlen (S._STR)  + 1] )     {        strcpy (_STR&NBSP;,&NBSP;S._STR); The     }        //assignment operator Overloads     //one.    This is problematic, in case new fails.     string& operator= (const string& s)     {         if (_STR&NBSP;!=&NBSP;S._STR)          {            delete[] _str;             _str = new char[sTrlen (S._STR)  + 1];            strcpy (_ STR,S._STR);        }         return *this;    }    //two .   on the above method improvement, first new Delete, If new fails, it will not affect the original content of _str     string& operator= (const string& s)      {        if (_STR&NBSP;!=&NBSP;S._STR)          {             Char *tmp = new char[strlen (S._STR)  + 1];             strcpy (TMP&NBSP;,&NBSP;S._STR);             delete[] _str;             _str =  tmp;        }    }    //   Deep copy   < modern notation >    string (const string& s)          :_str (NULL)     {         string tmp = s._str;        swap (_str  ,  tmp._str);     }        //the modern notation of the assignment operator:     string& operator= (const string& s)     {         if (_str ! =&NBSP;S._STR)         {             String tmp = s._str;             swap (_STR&NBSP;,&NBSP;TMP._STR);         }        return *this;    Modern notation for  }    //assignment Operators II:     string& operator= (String&  s)  //This copy constructs a temporary object S    {        if (_ STR&NBSP;!=&NBSP;S._STR)         {             swap (_STR&NBSP;,S._STR);//Exchange THIS-&GT;_STR and temporarily generated object data member S._str, leaving scope automatically destructors release         }        return * This;    }    ~string ()     {         if (_STR)         {             delete[] _str;             _str = NULL;        }         cout<< "~string ()" <<endl;    }    void  display ()     {        cout<<_str< <endl;    }private:    char *_str;}; Void test () {    string s1;    string s2 ("Hello");  &NBSP;&NBSP;&NBSP;STRING&NBSP;S3 (S2);    string s4 = s3;     s1. Display ();     s2. Display ();     s3. Display ();     s4. Display ();} Int main () {    test ();     return 0;}


This article is from the "vs LV" blog, so be sure to keep this source http://survive.blog.51cto.com/10728490/1752144

Brief analysis of "C + +" depth copy

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.