拷贝构造函数
拷贝构造函数用于从一个已存在的对象创建一个新的对象,即复制构造函数。它通常有一个类对象作为参数,返回一个新的对象,该对象与原始对象具有相同的值。如果一个类没有定义拷贝构造函数,则编译器会生成一个默认的拷贝构造函数,它将逐个复制所有非静态成员。如果一个类具有指针或引用成员,则需要自己编写拷贝构造函数,以确保正确地复制指针或引用所指向的对象。
移动构造函数和移动赋值运算符
移动构造函数和移动赋值运算符是 C++11 中引入的新特性,用于从一个临时对象创建一个新对象,以提高效率和减少内存使用。它们采用右值引用的语法,并将临时对象的资源移动到新对象中,而不是复制它们。如果一个类具有指针或其他资源成员,则需要实现移动构造函数和移动赋值运算符,以确保正确地移动这些资源。
移动构造函数和拷贝构造函数都是 C++ 中的构造函数,但是它们的功能和用途是不同的。下面是两者的区别:
1. 功能不同
拷贝构造函数用于从一个已存在的对象创建一个新的对象,即复制构造函数。它会复制原始对象的所有成员变量的值,从而创建一个新的、与原始对象相同的对象。
移动构造函数用于从一个右值引用的临时对象创建一个新的对象。它会“窃取”原始对象的资源(例如指针或文件句柄),并将其移动到新对象中,从而避免复制大量数据,提高性能和减少内存使用。
2. 形参类型不同
拷贝构造函数的参数通常是 const 引用类型的对象,例如:
MyClass(const MyClass& other);
移动构造函数的参数通常是右值引用类型的对象,例如:
MyClass(MyClass&& other);
3. 调用时机不同
拷贝构造函数通常在以下情况下被调用:
- 用一个对象初始化另一个对象
- 传递一个对象作为参数到函数中
- 从函数中返回一个对象
移动构造函数通常在以下情况下被调用:
- 从一个临时对象创建一个新对象
- 将一个临时对象作为参数传递到函数中
- 从函数中返回一个临时对象
4. 适用范围不同
拷贝构造函数适用于所有类型的对象,包括具有指针和资源的对象。
移动构造函数适用于具有可移动资源的对象,例如指针、文件句柄、unique_ptr 等,但不适用于具有固定位置内存的对象,例如数组、vector 等。
总之,拷贝构造函数和移动构造函数都是重要的构造函数,用于在不同的场合创建新的对象。它们在语法、功能、调用时机和适用范围等方面都有所不同,需要根据实际需要选择使用。
下面是一个使用移动构造函数的简单例子:
#include <iostream>
#include <string>
class MyString {
public:
MyString() : str(nullptr), len(0) {}
MyString(const char* s) : str(nullptr), len(0) {
if (s != nullptr) {
len = strlen(s);
str = new char[len + 1];
strcpy(str, s);
}
}
// 拷贝构造函数
MyString(const MyString& other) : str(nullptr), len(0) {
if (other.str != nullptr) {
len = other.len;
str = new char[len + 1];
strcpy(str, other.str);
}
}
// 移动构造函数
MyString(MyString&& other) noexcept {
str = other.str;
len = other.len;
other.str = nullptr;
other.len = 0;
}
~MyString() {
if (str != nullptr) {
delete[] str;
str = nullptr;
len = 0;
}
}
private:
char* str;
size_t len;
};
int main() {
MyString s1("Hello"); // 调用构造函数
MyString s2(s1); // 调用拷贝构造函数
MyString s3(std::move(s1)); // 调用移动构造函数
return 0;
}