C++ 类之拷贝控制
在C++中,拷贝控制(Copy Control)是指管理对象的复制、移动和销毁的机制。拷贝控制主要涉及以下五个成员函数:
- 拷贝构造函数(Copy Constructor)
- 拷贝赋值运算符(Copy Assignment Operator)
- 移动构造函数(Move Constructor)
- 移动赋值运算符(Move Assignment Operator)
- 析构函数(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>
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(); obj2.print(); obj3.print(); 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
|
总结
- 拷贝构造函数:用于通过另一个同类型的对象来初始化新对象。
- 拷贝赋值运算符:用于将一个已有对象的资源复制到另一个已有对象中。
- 移动构造函数:用于通过移动另一个同类型的对象来初始化新对象。
- 移动赋值运算符:用于将一个已有对象的资源移动到另一个已有对象中。
- 析构函数:用于在对象生命周期结束时清理资源。