Copy constructor and assignment function in C ++

Here we use the class String to introduce these two functions: the
copy constructor is a special constructor with a single formal parameter, the formal parameter (commonly used const modification) is a reference to the class type . When a new object is defined and initialized with an object of the same type, the copy constructor will be used explicitly. Why must the formal parameter be a reference to this type? Imagine that if the formal parameter is an instance of this class, because it is a parameter by value, we copy the formal parameter to the actual parameter and call the copy constructor. If the copy constructor is allowed to pass the value, the copy is called in the copy constructor Constructor, which forms endless recursive calls and causes stack overflow.

string(const string &s);
//类成员,无返回值

The assignment function is also overloaded by the assignment operator, because the assignment must be a member of the class, then its first operand is implicitly bound to the this pointer, that is, this is bound to the pointer to the left operand. Therefore, the assignment operator accepts a single formal parameter, and the formal parameter is an object of the same type. The right operand is generally passed as a const reference.

string(const string &s);
//类成员,无返回值

The copy constructor and assignment function are not used by every object. In addition, if they are not actively written, the compiler will automatically generate the default function in a "bit copy" way. In class design, "bit copying" should be prevented. If the class contains pointer variables, then these two default functions will fail. This involves deep copying and shallow copying.

There are two types of copy: deep copy , shallow copy.
When the equal sign assignment of the class appears, the copy function will be called. In the case where the display copy constructor is not defined, the system will call the default copy function-that is, shallow copy, which can Complete one by one copy of the members. When there is no pointer in the data member, shallow copy is feasible.
However, when there is a pointer in the data member, if a simple shallow copy is used, the two pointers in the two types will point to the same address , and when the object is about to end, the destructor will be called twice, causing the pointer to hang. Therefore, at this time, a deep copy must be used.
The difference between deep copy and shallow copy is that deep copy will apply for additional space in the heap memory to store data , which also solves the problem of pointer suspension. Point to different memory spaces, but the content is the same.
In short, when there is a pointer in the data member, you must use a deep copy .

class A{
	char * c;
}a, b;
 
//浅复制不会重新分配内存
//将a 赋给 b,缺省赋值函数的“位拷贝”意味着执行
a.c = b.c;
//从这行代码可以看出
//b.c 原有的内存没有释放
//a.c 和 b.c 指向同一块内存,任何一方的变动都会影响到另一方
//对象析构的时候,c 被释放了两次(a.c == b.c 指针一样)
 
//深复制需要自己处理里面的指针
class A{
	char *c;
	A& operator =(const A &b)
	{
		//隐含 this 指针
		if (this == &b)
			return *this;
		delete c;//释放原有内存资源
 
		//分配新的内存资源
		int length = strlen(b.c);
		c = new char[length + 1];
		strcpy(c, b.c);
 
		return *this;
	}
}a, b;
//这个是深复制,它有自定义的复制函数,赋值时,对指针动态分配了内存

Here is a summary of the specific differences between deep copy and shallow copy:

1. When the copy object state contains references to other objects, if the content pointed to by the reference object needs to be copied, instead of referring to the memory address, it is a deep copy, otherwise it is a shallow copy.
2. Shallow copy is the assignment between member data. When the value is copied, the two objects have common resources. The deep copy is to copy a resource first, the object has different resources (memory area), but the resource content (data in memory) is the same.
3. Unlike shallow copy, when deep copying handles references, if you change the content of the new object, it will not affect the original object content
. 4. Unlike deep copying, when the resource is released after shallow copying, the resource attribution may be unclear. (When the pointer is included, the resources of one party are released, in fact, the resources of the other party are also released accordingly), which causes the program to run incorrectly

Another difference between deep copy and shallow copy is that when executed, shallow copy directly copies the memory address, and deep copy needs to reopen the same size memory area and then copy the entire resource.

Well, with the previous foreshadowing, let ’s start talking about the copy constructor and assignment function. In fact, the first part has also introduced many

Here takes the string class as an example to illustrate

class String
{
public:
	String(const char *str = NULL);
	String(const String &rhs);
	String& operator=(const String &rhs);
	~String(void){
		delete[] m_data;
	}
 
private:
	char *m_data;
};
 
//构造函数
String::String(const char* str)
{
	if (NULL == str)
	{
		m_data = new char[1];
		*m_data = '\0';
	}
	else
	{
		m_data = new char[strlen(str) + 1];
		strcpy(m_data, str);
	}
}
 
//拷贝构造函数,无需检验参数的有效性
String::String(const String &rhs)
{
	m_data = new char[strlen(rhs.m_data) + 1];
	strcpy(m_data, rhs.m_data);
}
 
//赋值函数
String& String::operator=(const String &rhs)
{
	if (this == &rhs)
		return *this;
 
	delete[] m_data; m_data = NULL;
	m_data = new char[strlen(rhs.m_data) + 1];
	strcpy(m_data, rhs.m_data);
 
	return *this;

The difference between the String-like copy constructor and the ordinary constructor is that there is no need to compare with NULL at the function entry, because "reference" cannot be NULL, and "pointer" can be NULL. (This is an important difference between references and pointers). Then it is necessary to pay attention to the deep copy.
In comparison, the assignment function for the String class is much more complicated:

  1. First, you need to perform check self-assignment.
    This is to prevent self-copying and indirect copying, such as b = a; c = b; a = c; The copy operation will also go wrong, so this is a critical step. It should also be noted that the self-test checks the address, not the content, and the memory address is unique. Must be if (this == & rhs)

  2. To release the original memory resources,
    you must use delete to release the original memory resources. If you do not release it at this time, the memory address pointed to by this variable will no longer be the original memory address, and you will not be able to release the memory, causing memory leaks.

  3. Allocate new memory resources and copy the resources
    so that the memory address pointed by the variable has changed, but the resources inside are the same

  4. Returning a reference to this object The
    purpose of this is to achieve a chain expression like a = b = c ;, pay attention to return * this.

But think about it carefully, the above program does not take into account the safety of exceptions , we use delete to free the memory of the original instance before allocating memory, if there is insufficient memory later to throw an exception, then the m_data of the previous delete will be a null pointer , This is very easy to cause the program to crash, so we can change the order, that is, first an instance memory, and then use delete to release the original memory space, and finally use m_data to assign the new pointer.

Next, talk about the difference between the copy constructor and the assignment function.

Copy constructor and assignment function are very easy to confuse, often lead to miswriting and misuse. The copy constructor is called when the object is created, while the assignment function can only be called on an existing object. Look at the code below:

String a("hello");
	String b("world");
 
	String c = a;//这里c对象被创建调用的是拷贝构造函数
	             //一般是写成 c(a);这里是与后面比较
	c = b;//前面c对象已经创建,所以这里是赋值函数

The above shows that the place where "=" is not necessarily called the assignment function (arithmetic overloaded function), it is also possible to copy the constructor, so when is the copy constructor called, and when is the assignment function called? The standard of judgment is actually very simple: if the temporary variable appears for the first time, then the copy constructor can only be called, otherwise if the variable already exists, then the assignment function is called

Reference:
Transfer from selfimpr1991

A great god's blog about the difference and implementation of constructor, copy constructor and assignment function

Detailed introduction

Published 13 original articles · praised 5 · visits 459

Guess you like

Origin blog.csdn.net/why18767183086/article/details/104164117