現實中充滿「所有權轉移」場景:銀行轉賬(錢從戶 A 移至戶 B)、換手機移 SIM 卡、剪切文件。C++11 前,這類場景只能通過深拷貝實現:分配新記憶體、逐字節複製、釋放舊記憶體——既慢又可能拋異常。
C++11 引入移動語義:直接將資源控制權從源對象「偷」給目標對象,源對象置為空狀態。零拷貝、零分配、極快。
ClassName(ClassName&& other) noexcept {
// 1. 接管 other 的資源
// 2. 將 other 置為有效的空狀態
}
ClassName&&:右值引用,綁定到臨時對象或 std::move(x)noexcept:標準庫容器要求移動構造不拋異常,否則退化用拷貝class IntNum {
int* xptr;
public:
IntNum(int x = 0) : xptr(new int(x)) { cout << "構造\n"; }
IntNum(const IntNum& n) : xptr(new int(*n.xptr)) { cout << "拷貝構造\n"; }
~IntNum() { delete xptr; cout << "析構\n"; }
int getInt() const { return *xptr; }
};
IntNum getNum() {
IntNum a; // 構造
return a; // 拷貝構造臨時對象 → 拷貝構造返回值 → 析構 a → 析構臨時對象
}
int main() {
cout << getNum().getInt() << endl;
}
// 輸出:
// 構造
// 拷貝構造
// 析構
// 拷貝構造
// 析構
// 0
// 析構
class IntNum {
int* xptr;
public:
IntNum(int x = 0) : xptr(new int(x)) { cout << "構造\n"; }
IntNum(const IntNum& n) : xptr(new int(*n.xptr)) { cout << "拷貝構造\n"; }
IntNum(IntNum&& n) noexcept : xptr(n.xptr) { // 移動構造
n.xptr = nullptr; // 關鍵:置空源對象
cout << "移動構造\n";
}
~IntNum() { delete xptr; cout << "析構\n"; }
int getInt() const { return *xptr; }
};
IntNum getNum() {
IntNum a;
return a; // NRVO 優化下可能直接構造在返回值位置,否則觸發移動構造
}
int main() {
cout << getNum().getInt() << endl;
}
// 典型輸出(無 NRVO 時):
// 構造
// 移動構造
// 析構
// 0
// 析構
| 場景 | 示例 |
|---|---|
| 函數按值返回局部對象 | return a; (非 NRVO 時) |
| 用 std::move 顯式轉換 | IntNum b(std::move(a)); |
| 臨時對象初始化 | IntNum c = getNum(); |
| 容器重新分配/擴容 | vector.push_back(std::move(x)); |
| 插入右值 | vec.emplace_back(10); |
完整的資源管理類需實現「五大函數」:
class Resource {
int* data;
size_t size;
public:
// 1. 構造
Resource(size_t n = 0) : data(n ? new int[n] : nullptr), size(n) {}
// 2. 析構
~Resource() { delete[] data; }
// 3. 拷貝構造
Resource(const Resource& other) : data(new int[other.size]), size(other.size) {
copy(other.data, other.data + size, data);
}
// 4. 移動構造
Resource(Resource&& other) noexcept : data(other.data), size(other.size) {
other.data = nullptr; other.size = 0;
}
// 5. 拷貝賦值
Resource& operator=(const Resource& other) {
if (this != &other) {
delete[] data;
data = new int[other.size]; size = other.size;
copy(other.data, other.data + size, data);
}
return *this;
}
// 6. 移動賦值
Resource& operator=(Resource&& other) noexcept {
if (this != &other) {
delete[] data;
data = other.data; size = other.size;
other.data = nullptr; other.size = 0;
}
return *this;
}
};
vectorv; v.reserve(10000); for (int i = 0; i < 10000; ++i) v.emplace_back(1000); // 只有構造,無拷貝/移動 vector v2; for (int i = 0; i < 10000; ++i) v2.push_back(Resource(1000)); // 觸發移動構造 // 移動版比拷貝版快 10~100 倍(視對象大小)
noexcept,啟用容器優化std::move、emplace_back、返回值優化(RVO/NRVO)mutex、unique_ptr 的拷貝)由編譯器強制檢查移動語義是 C++11 性能革命的核心之一,將「值語義」的高級抽象與「引用語義」的零成本轉移完美結合,讓 C++ 真正實現了「不為不用的特性付費」。