C++ 类之拷贝控制

C++ 类之拷贝控制

在C++中,拷贝控制(Copy Control)是指管理对象的复制、移动和销毁的机制。拷贝控制主要涉及以下五个成员函数:

  1. 拷贝构造函数(Copy Constructor)
  2. 拷贝赋值运算符(Copy Assignment Operator)
  3. 移动构造函数(Move Constructor)
  4. 移动赋值运算符(Move Assignment Operator)
  5. 析构函数(Destructor)

这些成员函数共同负责对象的生命周期管理,包括对象的创建、复制、移动和销毁。

1. 拷贝构造函数

拷贝构造函数用于通过另一个同类型的对象来初始化新对象。它通常用于复制对象的资源。

示例

1
2
3
4
5
6
7
8
9
class MyClass {
public:
MyClass(const MyClass& other) : a(other.a) {
// 拷贝构造函数
}

private:
int a;
};

2. 拷贝赋值运算符

拷贝赋值运算符用于将一个已有对象的资源复制到另一个已有对象中。

示例

1
2
3
4
5
6
7
8
9
10
11
12
class MyClass {
public:
MyClass& operator=(const MyClass& other) {
if (this != &other) {
a = other.a;
}
return *this;
}

private:
int a;
};

3. 移动构造函数

移动构造函数用于通过移动另一个同类型的对象来初始化新对象。它通常用于转移对象的资源,而不是复制它们。

示例

1
2
3
4
5
6
7
8
9
10
class MyClass {
public:
MyClass(MyClass&& other) noexcept : a(other.a) {
other.a = nullptr;
// 移动构造函数
}

private:
int* a;
};

4. 移动赋值运算符

移动赋值运算符用于将一个已有对象的资源移动到另一个已有对象中。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyClass {
public:
MyClass& operator=(MyClass&& other) noexcept {
if (this != &other) {
delete a;
a = other.a;
other.a = nullptr;
}
return *this;
}

private:
int* a;
};

5. 析构函数

析构函数用于在对象生命周期结束时清理资源。它的名称与类名相同,但前面有一个波浪号(~)。

示例

1
2
3
4
5
6
class MyClass {
public:
~MyClass() {
// 析构函数
}
};

拷贝控制的规则

C++11引入了”Rule of Three”和”Rule of Five”来帮助开发者管理拷贝控制函数。

Rule of Three

如果一个类需要自定义拷贝构造函数、拷贝赋值运算符或析构函数中的任何一个,那么它很可能需要自定义所有这三个函数。

Rule of Five

C++11引入了移动语义,因此如果一个类需要自定义拷贝构造函数、拷贝赋值运算符、移动构造函数、移动赋值运算符或析构函数中的任何一个,那么它很可能需要自定义所有这五个函数。

完整示例

以下是一个包含所有拷贝控制函数的完整示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include <iostream>
#include <utility> // for std::move

class MyClass {
public:
// 默认构造函数
MyClass() : a(nullptr) {
std::cout << "Default constructor" << std::endl;
}

// 参数化构造函数
MyClass(int x) : a(new int(x)) {
std::cout << "Parameterized constructor" << std::endl;
}

// 拷贝构造函数
MyClass(const MyClass& other) : a(new int(*other.a)) {
std::cout << "Copy constructor" << std::endl;
}

// 移动构造函数
MyClass(MyClass&& other) noexcept : a(other.a) {
other.a = nullptr;
std::cout << "Move constructor" << std::endl;
}

// 拷贝赋值运算符
MyClass& operator=(const MyClass& other) {
if (this != &other) {
delete a;
a = new int(*other.a);
std::cout << "Copy assignment operator" << std::endl;
}
return *this;
}

// 移动赋值运算符
MyClass& operator=(MyClass&& other) noexcept {
if (this != &other) {
delete a;
a = other.a;
other.a = nullptr;
std::cout << "Move assignment operator" << std::endl;
}
return *this;
}

// 析构函数
~MyClass() {
delete a;
std::cout << "Destructor" << std::endl;
}

// 打印数据
void print() const {
if (a) {
std::cout << "a: " << *a << std::endl;
} else {
std::cout << "a is null" << std::endl;
}
}

private:
int* a;
};

int main() {
MyClass obj1(10); // 调用参数化构造函数
MyClass obj2 = obj1; // 调用拷贝构造函数
MyClass obj3 = std::move(obj1); // 调用移动构造函数

MyClass obj4(20); // 调用参数化构造函数
obj4 = obj2; // 调用拷贝赋值运算符
obj4 = std::move(obj3); // 调用移动赋值运算符

obj1.print(); // 被移动后,obj1 的值被重置
obj2.print();
obj3.print(); // 被移动后,obj3 的值被重置
obj4.print();

return 0;
}

输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Parameterized constructor
Copy constructor
Move constructor
Parameterized constructor
Copy assignment operator
Move assignment operator
a is null
a: 10
a is null
a: 10
Destructor
Destructor
Destructor
Destructor

总结

  • 拷贝构造函数:用于通过另一个同类型的对象来初始化新对象。
  • 拷贝赋值运算符:用于将一个已有对象的资源复制到另一个已有对象中。
  • 移动构造函数:用于通过移动另一个同类型的对象来初始化新对象。
  • 移动赋值运算符:用于将一个已有对象的资源移动到另一个已有对象中。
  • 析构函数:用于在对象生命周期结束时清理资源。

C++ 类之拷贝控制
https://linhanmic.github.io/2023/10/05/C++ 类之拷贝控制/
作者
Linhanmic
发布于
2023年10月5日
更新于
2024年9月13日
许可协议