帝国做双语网站,safari浏览器下载,wordpress 百度统计插件,个人征信网上查询系统很多人在学习 C 时#xff0c;第一次看到下面这两个函数会一脸懵#xff1a;Box(Box other); // 移动构造 Box operator(Box other); // 移动赋值这两个函数看起来像“高级语法”#xff0c; 但实际上它们不是凭空出现的#xff0c;而…很多人在学习 C 时第一次看到下面这两个函数会一脸懵Box(Box other); // 移动构造 Box operator(Box other); // 移动赋值这两个函数看起来像“高级语法”但实际上它们不是凭空出现的而是被性能问题 临时对象浪费一步步逼出来的进化结果。本文从“问题”出发再用一个完整可运行的例子把它讲透。一、最初阶段只有拷贝构造最早 C 只有拷贝语义Box(const Box other);含义就是复制一份资源示例Box a(10); Box b a; // 拷贝构造如果资源很小问题不大。但当成员是std::stringstd::vector大数组文件句柄网络连接复制就会变得慢 占内存。二、问题升级临时对象的浪费看一个常见函数Box createBox() { Box b(10); return b; }调用Box a createBox();如果只有拷贝构造流程是构造 b 拷贝构造 a 析构 b问题在于b 马上要死了还完整复制一份资源纯浪费。于是一个需求出现了能不能不复制而是“搬走资源”三、移动语义诞生 —— “搬家”而不是“复印”移动语义的核心思想如果对象马上要被销毁就不要复制资源直接转移所有权。这就引出了移动构造和移动赋值。四、完整示例代码核心下面是一个完整可运行的类包含构造拷贝构造移动构造拷贝赋值移动赋值析构#include iostream using namespace std; class Box { public: int* data; // 构造 Box(int v) { data new int(v); cout 构造\n; } // 拷贝构造 Box(const Box other) { data new int(*other.data); cout 拷贝构造\n; } // 移动构造 Box(Box other) { data other.data; // 接管资源 other.data nullptr; // 清空对方 cout 移动构造\n; } // 拷贝赋值 Box operator(const Box other) { cout 拷贝赋值\n; if (this other) return *this; delete data; data new int(*other.data); return *this; } // 移动赋值 Box operator(Box other) { cout 移动赋值\n; if (this other) return *this; delete data; // 释放旧资源 data other.data; // 接管资源 other.data nullptr; // 清空对方 return *this; } ~Box() { delete data; cout 析构\n; } }; Box createBox() { Box b(10); return b; } int main() { cout 移动构造示例 \n; Box a createBox(); // 触发移动构造或RVO cout 移动赋值示例 \n; Box b(1); b createBox(); // 触发移动赋值 }五、可能看到的输出不同编译器略有差异常见输出 移动构造示例 构造 移动构造 析构 析构 移动赋值示例 构造 构造 移动赋值 析构 析构有时你只会看到构造那是RVO返回值优化在工作 ——编译器直接在目标位置构造对象连移动都省掉了。六、移动构造 vs 移动赋值区别类型场景是否已有资源核心动作移动构造新对象创建没有直接接管资源移动赋值对象已存在有先释放再接管七、为什么要把对方清空other.data nullptr;原因不清空 → 析构 double free 清空 → delete nullptr 安全八、现实类比拷贝构造 复印整箱书 移动构造 把箱子搬走 拷贝赋值 先扔旧书再复印新书 移动赋值 先扔旧书再搬新箱子九、终极锚点总结拷贝构造 → 复制资源 移动构造 → 搬资源给新对象 拷贝赋值 → 复制资源给已有对象 移动赋值 → 清空自己再搬资源移动语义不是复杂语法它是“拷贝太贵”被逼出来的性能进化。当你理解资源复制 vs 资源转移移动构造和移动赋值就再也不会混了。