C++ copy constructor

copy constructor

We often use a variable to initialize a variable of the same type, so there should be similar operations for custom types, so how to use an existing object to create another same object when creating an object?

Constructor: There is only a single parameter, which is a reference to an object of this class type (usually const modified), which is automatically called by the compiler when a new object is created with an existing class type object

The copy constructor is an overload of the constructor, so if the copy constructor is explicitly defined, the compiler will no longer generate the constructor by default.

feature

Copy construction is also a special member function

Features are as follows:

  • Copy construction is an overload of the constructor;
  • There is only one parameter of the copy construction and the type must be a reference to the class, instead of calling by value, otherwise it will recurse infinitely;
  • If no copy constructor is explicitly defined, the compiler will generate a default copy constructor by itself. The default copy constructor object is copied according to memory storage and byte order, also called shallow copy;
class Date
{
public:
	Date(int year, int month, int day)
		:
		_year(year),
		_month(month),
		_day(day)
	{}
	void Display()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1(2001, 7, 28);
	Date d2(d1);
	d1.Display();
	d2.Display();
	return 0;
}

output:

2001-7-28

2001-7-28

  • For those classes that directly manage memory resources (including pointer variables), is a simple value copy still worth it? Obviously can't stand it.

Explanation by illustration:

Two objects of the string class point to the same space. Isn't this messed up? If one of the objects changes the data pointing to the memory through the pointer, the other object will also be affected. This is something we don't want to happen. We Each object is expected to function independently.

The following program will crash

class String
{
public:
	String(const char* str = "songxin")
	{
		cout << "String(const char* str = \"songxin\")" << endl;
		_str = (char*)malloc(strlen(str) + 1);
		strcpy(_str, str);
	}
	~String()
	{
		cout << "~String()" << endl;
		free(_str);
		_str = nullptr;
	}
private:
	char* _str;
};
int main()
{
	String s1;
	String s2(s1);
	return 0;
}

The reason is that the member pointers of the two string classes both point to a piece of memory, and they respectively call the destructor once, which is equivalent to releasing the same memory space twice, and the program crashes.

Therefore, for objects in this situation, we can no longer use the default copy construction generated by the compiler, but can only explicitly define the copy construction and implement deep copying.

Compiler-generated copy construction

What does the copy construct generated by the compiler by default do?

  • For built-in type members

​ Complete the value copy;

  • For custom type members

    call the member's copy constructor;

class Time
{
public:
	Time(int hour = 0, int minute = 0, int second = 0)
		:
		_hour(hour),
		_minute(minute),
		_second(second)
	{}
	Time(Time& t)
	{
		_hour = t._hour;
		_minute = t._minute;
		_second = t._second;
	}
private:
	int _hour;
	int _minute;
	int _second;
};
Time top(0, 1, 1);
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1, Time& t = top)
		:
		_year(year),
		_month(month),
		_day(day),
		_t(t)
	{}
private:
	int _year;
	int _month;
	int _day;
	Time _t;
};
int main()
{
	Time t(1, 1, 1);
	Date d1(2001, 7, 28,t);
	Date d2(d1);
	return 0;
}

If the default generated copy construction does not call the copy construction of the Time class member, then the value of _t of d2 should be (_hour = 0, _minute = 0, _second = 0), and the final result here is _t in d2 and The _t value in d2 is the same.

Here, the built-in type of the automatically generated copy constructor in the Date class will be copied in byte order, and the copy constructor of Time is called for the custom type _t.

copy-constructed initialization list

The copy constructor is an overload of the constructor, so the copy constructor also has an initialization list, so it is also recommended to complete the initialization of the object in the initialization list phase to develop a good habit.

When it is possible not to explicitly define a copy constructor

  • member variables have no pointers;
  • Members have pointers, but do not manage memory resources;

The pitfalls of explicitly defining copy construction

There has always been this misunderstanding:

We all know that the constructor generated by the compiler will call the constructor of the member in the initialization list, and when we explicitly define the constructor, even if we do not write it, the constructor of the member of the custom type will be called in the initialization list.

By analogy, I made a low-level mistake:

That is, since the copy construction generated by the compiler can automatically call the copy construction of the custom member in the initialization list, then even if we do not write the explicitly defined copy construction, the copy construction of the custom member will be automatically called in the initialization list.

So I wrote the following code:

class Time
{
public:
	Time(int hour = 0, int minute = 0, int second = 0)
		:
		_hour(hour),
		_minute(minute),
		_second(second)
	{}
	Time(Time& t)
	{
		_hour = t._hour;
		_minute = t._minute;
		_second = t._second;
	}
private:
	int _hour;
	int _minute;
	int _second;
};
Time top(2, 2, 2);
class Date
{
public:
	Date(int year = 1900, int month = 1, int day = 1, Time& t = top)
		:
		_year(year),
		_month(month),
		_day(day),
		_t(t)
	{}
	Date(Date& d)//Explicitly defined copy construction
	{

	}
private:
	int _year;
	int _month;
	int _day;
	Time _t;
};
int main()
{
	Time t(1, 1, 1);
	Date d1(2001, 7, 28,t);
	Date d2(d1);
	return 0;
}

View the value after d2 calls the copy construction through the watch window:

The copy was not successful.

I only care about comparing their functions, but I just ignore that copy construction is also a kind of constructor, so the natural initialization list is the same as ordinary construction, it will call the constructor of the custom class, not dealing with built-in types. It's just that the compiler generates the processed constructor to achieve the effect of copying. (so stupid for this mistake)

in conclusion:

The copy constructor is a type of constructor. It also has an initialization list. If it is a copy constructor generated by the compiler, it will copy the built-in type in byte order, and will call the copy construction of the custom member for the custom type member.

But if it is a copy constructor that we explicitly define, it also has an initialization list, but its initialization list does not call the copy constructor of members, but like ordinary constructors, it does not initialize values ​​for built-in type members. , for a custom type member to call the custom member's constructor instead of the copy constructor.

Tags: C++ Visual Studio programming language

Posted by mad81 on Wed, 25 May 2022 10:40:27 +0300