移动构造函数(Move Constructor)是 C++11 引入的重要特性,用于高效转移资源(如动态内存、文件句柄等)的所有权,**避免不必要的深拷贝**,提升程序性能。以下是其核心要点和实践指南:
---
### **1. 移动构造函数的作用**
- **资源高效转移**:将资源从一个对象(通常是临时对象或即将销毁的对象)转移到新对象,而非复制。
- **性能优化**:避免深拷贝大对象(如动态数组、容器),显著减少内存操作。
- **支持移动语义**:与 `std::move` 结合使用,显式触发资源转移。
---
### **2. 语法与实现**
- **语法**:接受右值引用(`&&`)作为参数,并标记为 `noexcept`(关键异常安全)。
```cpp
class MyClass {
public:
// 移动构造函数
MyClass(MyClass&& other) noexcept
: data(other.data), size(other.size) {
other.data = nullptr; // 置空原对象指针,避免资源被释放
other.size = 0;
}
private:
int* data;
size_t size;
};
```
- **关键步骤**:
1. **转移资源**:直接将原对象的资源指针/句柄赋值给新对象。
2. **置空原对象**:将原对象的资源指针设为 `nullptr`(或等效操作),确保其析构时不会释放已转移的资源。
---
### **3. 触发场景**
- **临时对象传递**:
```cpp
MyClass createObject() {
MyClass tmp;
return tmp; // 触发移动构造(编译器优化可能直接消除拷贝)
}
MyClass obj = createObject(); // 移动构造函数被调用
```
- **显式使用 `std::move`**:
```cpp
MyClass obj1;
MyClass obj2 = std::move(obj1); // 移动构造,obj1 不再拥有资源
```
---
### **4. 注意事项**
- **资源所有权转移后**:原对象应处于“有效但未定义”状态(如空指针),确保其析构函数不会误操作。
- **异常安全**:标记为 `noexcept`,否则某些标准库操作(如 `std::vector` 扩容)可能回退到拷贝而非移动。
- **与拷贝构造区分**:
```cpp
// 拷贝构造函数(深拷贝)
MyClass(const MyClass& other) : data(new int[other.size]), size(other.size) {
std::copy(other.data, other.data + size, data);
}
// 移动构造函数(资源转移)
MyClass(MyClass&& other) noexcept : data(other.data), size(other.size) {
other.data = nullptr;
}
```
- **手动管理资源时必实现**:若类管理动态内存、文件句柄等资源,需手动定义移动构造函数(否则编译器可能禁用移动语义)。
---
### **5. 示例:文件句柄的移动**
```cpp
class FileHandler {
public:
FileHandler(const char* filename) : file(fopen(filename, "r")) {}
// 移动构造函数
FileHandler(FileHandler&& other) noexcept : file(other.file) {
other.file = nullptr; // 原对象不再持有文件
}
~FileHandler() {
if (file) fclose(file);
}
private:
FILE* file;
};
// 使用示例
FileHandler f1("data.txt");
FileHandler f2 = std::move(f1); // f1 的句柄转移给 f2
```
---
### **6. 编译器行为**
- **默认移动构造函数**:若未定义移动构造函数且未显式删除拷贝操作,编译器会生成默认的移动构造函数(按成员移动)。
- **禁用移动语义**:若用户定义了拷贝构造函数/析构函数/拷贝赋值运算符,编译器不会生成默认移动构造函数(需手动实现)。
---
### **总结**
移动构造函数是 C++ 高效资源管理的核心工具,**适用于资源密集型对象**。通过转移而非拷贝资源,结合右值引用和 `std::move`,可显著优化性能。实践中需注意资源所有权的清晰转移和异常安全,避免悬空指针或资源泄漏。