Differences between C++ copy constructors and overloaded assignment operators

Posted by lanrat on Tue, 13 Aug 2019 03:40:58 +0200

copy constructor

Starting with the constructor, in C++ object-oriented design, each object represents an entity of an abstract collection, and each entity needs its own memory space in the current running process, that is, the object has space when it exists.To do this, C++ introduces constructors to instantiate objects and allows the compiler to request space for the object from the operating system so that it can exist in the operating system.

The copy constructor is a constructor that assigns one-to-one data members of the old object to the new data members of the object, that is, the result of the copy constructor is identical to the constructor, and new objects are generated.
View the following code:

#include <iostream>
using namespace std;

class A{
public:
    A(){ cout << "default constructor " << endl;  }
    A(int a) {num=a;cout << "constructor with param" << endl; }
    A(const A &a)
    {
        num=a.num;
        cout << "copy constructor " << endl;
    }
    ~A(){ cout << "destructor " << this->num << endl; }
    void print()
    {
        cout << this->num << endl;
    }

private:
    int num;

};
void para_copy(A &a)
{
}
int main()
{
    A a(100); // overloaded constructor
    A a1=a; //copy constructor
    a1.print();
    A c;//Default constructor
    return 0;
}

The output is as follows:

constructor with param //a Overload Construction
copy constructor //a1 copy construction
100
default constructor //c Default Construction
destructor 0 //c Destruction
destructor 100 //a1 Destruction
destructor 100 //a Destruction

The copy constructor call scenario is as follows:

  • As in the code above, one object is initialized by another object
  • Object as function parameter
  • Object as function return value
    For the object as a function parameter and the copy constructor that is called when the value is returned, see the code below
    #include <iostream>
    using namespace std;
    
    class A{
    public:
        A(){ cout << "default constructor " << endl;  }
        A(int a) {num=a;cout << "constructor with param" << endl; }
        A(const A &a)
        {
            num=a.num;
            cout << "copy constructor " << endl;
        }
        ~A(){ cout << "destructor " << this->num << endl; }
        void print()
        {
            cout << this->num << endl;
        }
    
    private:
        int num;
    
    };
    void param_copy(A a)
    {
        cout << "param obj" << endl;
    }
    A return_value()
    {
        A d(0);
        cout << "return obj" << endl;
        return d;
    }
    int main()
    {
        A c;
        param_copy(c);
        return_value();
        return 0;
    }
    
    The output is as follows
    default constructor  //c Default Construction
    copy constructor // Object as parameter, copy to temporary object
    param obj
    destructor 0 // Destruct Temporary Objects
    constructor with param //The d object in function return_value uses an overloaded constructor
    return obj 
    destructor 0 //Destruct d object, local variable
    destructor 0 //Destruct c object
    

The description of deep and shallow copies is as follows:

  1. Typically, the default-generated copy constructors and assignment operators simply copy the values.If the data members of a class have pointers, copying by value transfer alone will cause the member pointers of two objects to point to the same block of memory, and the same memory will be freed twice when two objects are destructed, causing the pointer to hang empty.

  2. Deep copy is the second case above where the copy constructor uses deep copy when there is a pointer variable in the data member, that is, the address space of the initialization object is reassigned in the constructor.

    The code is as follows:

    #include <iostream>
    using namespace std;
    
    class A{
    public:
        A(){ p=new int(10);cout << "default constructor " << endl;  }
        //A(int a) {num=a;cout << "constructor with param" << endl; }
        A(const A &a)
        {
            num=a.num;
            p=new int(10);
            *p=*(a.p);
            cout << "copy constructor " << endl;
        }
        ~A(){ cout << "destructor " << this->num << endl; }
        void print()
        {
            if(p!=NULL)
            {
              delete p;
              cout << this->num << endl;
            }
        }
    
    private:
        int num;
        int *p;
    
    };
    void param_copy(A a)
    {
        cout << "param obj" << endl;
    }
    int main()
    {
        A c;
        A b(c);
        return 0;
    }
    

Overloaded assignment operator

The biggest difference between assignment operators and copy constructors is that assignment operators do not generate new objects, while copy constructors generate new objects.

#include <iostream>
using namespace std;

class Person
{
public:
    Person(){}
    Person(const Person& p)
    {
        cout << "Copy Constructor" << endl;
    }
 
    Person& operator=(const Person& p)
    {
        cout << "Assign" << endl;
        return *this;
    }
 
private:
    int age;
    string name;
};
 
void f(Person p)
{
    return;
}
 
Person f1()
{
    Person p;
    return p;
}
 
int main()
{
    Person p;
    Person p1 = p;    // A
    cout <<" p1 addr " <<  &p1 << endl;
    Person p2;
    cout <<" p2 addr " <<  &p2 << endl;
    p2 = p;           // B
    cout <<" p2 addr after asign " <<  &p2 << endl;
    f(p2);            // C f Function Parameters
    cout <<" p2 addr after asign " <<  &p2 << endl;
 
    p2 = f1();        // If the return value of D f1 is a change of object, copy construction is performed first, and the returned object is assigned to p2
    cout <<" p2 addr after asign " <<  &p2 << endl;
 
    Person p3 = f1(); // E Generates a new object, which is a copy constructor
    cout <<" p3 addr " <<  &p3 << endl;
 
    getchar();
    return 0;
}

The output is as follows:

Copy Constructor //A
Assign //B
Copy Constructor //C
Copy Constructor //D
Assign //D
Copy Constructor //E