【ChernoC++笔记】移动赋值运算符
【90】【Cherno C++】【中字】stdmove与移动赋值操作符
▶️移动构造与std::move#
接上节的String类,我们可以通过string来构造新的对象dest:
// 拷贝构造
String string = "Hello";
String dest = string;
为了使用移动构造函数,string需要cast为临时变量:
// 移动构造
String dest = (string&&)string;
// 写法等价于
String dest((string&&)string);
这种cast方法并不是对每个类型都适用,例如,auto类型不能这样静态地推导。➡️➡️std::move
// 更优雅地移动构造
String dest(std::move(string));
如果你需要把一个已经存在的变量变成临时变量,可以标记它,表示你可以从这个特定的变量中偷取资源。即,使用std::move将其变成临时变量,这样就可以使用移动构造函数或移动赋值操作符来进行移动,从那个对象中获取资源。
▶️赋值操作符#
以上操作都构造了一个新对象,这和接下来要说的赋值不同。
*赋值操作符:只有当把一个变量赋值给一个已有的变量时才会被调用。例如:
String string = "Hello";
// 构造
String dest(std::move(string));
// 赋值
dest = std::move(string);
此处的=
运算符实际就是对现有变量的赋值运算符。
▶️移动赋值函数:实际上是把另一个对象移到当前对象中。#
// 移动赋值函数
String& operator=(String&& other) noexcept {
printf("Moved!\\n");
m_Size = other.m_Size;
m_Data = other.m_Data;
other.m_Data = nullptr;
other.m_Size = 0;
}
-
要赋值就需要覆盖当前对象,因为当前对象可能已经分配了一些内存。但是,如果直接将m_Data等于other.m_Data,就会造成内存泄漏,因为我们没有办法删除旧的数据。所以我们需要先删除旧数据:
String& operator=(String&& other) noexcept { printf("Moved!\\n"); delete[] m_Data; // 删除当前对象的旧数据 m_Size = other.m_Size; m_Data = other.m_Data; other.m_Data = nullptr; other.m_Size = 0; }
-
通常在赋值操作符中,还需要保证当前对象不等于other对象(自赋值操作)。不可以进行如下操作:
dest = std::move(dest);
自赋值操作时,移动赋值函数会删除dest数据,丢失数据。为了防止这种情况发生:
String& operator=(String&& other) noexcept { printf("Moved!\\n"); // 判断是否有自赋值操作 if(this != &other) { delete[] m_Data; m_Size = other.m_Size; m_Data = other.m_Data; other.m_Data = nullptr; other.m_Size = 0; } return *this; }
-
测试的main函数:
int main() { String apple = "Apple"; String dest = "Dest"; std::cout << "Apple: "; apple.Print(); std::cout << "dest: "; dest.Print(); dest = std::move(apple); std::cout << "Apple: "; apple.Print(); std::cout << "dest: "; dest.Print(); std::cin.get(); }
打印如下:
Created! // 创建apple Created! // 创建dest Apple: Apple // apple.Print() dest: Dest // dest.Print() Moved! // 移动赋值操作 Apple: // apple为空,内存被偷走 dest: Apple // dest为Apple Destroyed! Destroyed!
移动赋值使apple被设置为空,dest被设置为Apple,即转移了整个字符数组的所有权,没有做任何复制、分配或解除分配,相当于交换了两个变量。
❓移动构造和移动赋值的区别?#
虽然都有用到=
符号,但移动构造函数是构造了一个新对象,移动赋值运算符是对已存在的对象赋值。
// 移动构造
String dest = std::move(apple);
// 移动赋值
dest = std::move(apple);
// 等价于
dest.operator=(std::move(apple));
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!