首页 > 编程语言 >【ChernoC++笔记】移动赋值运算符

【ChernoC++笔记】移动赋值运算符

时间:2023-07-11 17:36:06浏览次数:64  
标签:Cherno String dest C++ 运算符 other Data string 赋值

【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;
}
  1. 要赋值就需要覆盖当前对象,因为当前对象可能已经分配了一些内存。但是,如果直接将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;
    }
  2. 通常在赋值操作符中,还需要保证当前对象不等于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;
    }
  3. 测试的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));

标签:Cherno,String,dest,C++,运算符,other,Data,string,赋值
From: https://www.cnblogs.com/rthete/p/17545389.html

相关文章

  • 第三节 运算符
    1.运算符和表达式运算符:​ 就是对常量或者变量进行操作的符号。​ 比如:+-*/表达式:​ 用运算符把常量或者变量连接起来的,符合Java语法的式子就是表达式。​ 比如:a+b这个整体就是表达式。​ 而其中+是算术运算符的一种,所以这个表达式也称之为算术表达式。2.算术运......
  • 104.C++中标准库是什么?
    104.C++中标准库是什么?1.C++标准库可以分为两部分:1.1标准函数库:这个库是由通用的、独立的、不属于任何类的函数组成的。函数库继承自C语言。输入/输出I/O、字符串和字符处理、数学、时间、日期和本地化、动态分配、其他、宽字符函数*输入输出流:`<iostream>`头文件中的......
  • 98.C++如何处理多个异常的?
    98.C++如何处理多个异常的?C++中的异常情况:语法错误(编译错误):比如变量未定义、括号不匹配、关键字拼写错误等等编译器在编译时能发现的错误,这类错误可以及时被编译器发现,而且可以及时知道出错的位置及原因,方便改正。运行时错误:比如数组下标越界、系统内存不足等等。这类错误不易......
  • 77.C++中的指针参数传递和引用参数传递有什么区别?底层原理你知道吗?
    77.C++中的指针参数传递和引用参数传递有什么区别?底层原理你知道吗?1.指针参数传递本质上是值传递,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,会在栈中开辟内存空间以存放由主调函数传递进来的实参值,从而形成了实参的一个副本(替身)。值传......
  • 81.知道C++中的组合吗?它与继承相比有什么优缺点吗?
    81.知道C++中的组合吗?它与继承相比有什么优缺点吗?1.继承继承是Isa的关系,比如说Student继承Person,则说明StudentisaPerson。继承的优点是子类可以重写父类的方法来方便地实现对父类的扩展。继承的缺点有以下几点:①父类的内部细节对子类是可见的。②子类从父类继承的方法......
  • PAT-甲级-1004 Counting Leaves C++
    Afamilyhierarchyisusuallypresentedbyapedigreetree.Yourjobistocountthosefamilymemberswhohavenochild.InputSpecification:Eachinputfilecontainsonetestcase.Eachcasestartswithalinecontaining 0<N<100,thenumberofnode......
  • 逻辑运算符
     rint(1and5or0)#先计算1and5为5再计算5or0为5print(1or5and0or6and0)"""先计算5and0为0,6and0为0整个语句就变为1or0or0结果为1""" ......
  • Visual Studio C++ 相关使用技巧(持续更新)
    0.目的Startedin2023-07-1113:45:55记录VisualStudioC++的一些问题、配置步骤,用于提升效率。主要用VS2022版本,偶尔用VS2019。1.关闭inlayhints函数的参数前面,显示了类型。有时候感觉很碍眼。在VSCode里这称为inlayhints。在VS2022中文版本中,称为“启......
  • 动态数组和C++ std::vector详解
    目录1.std::vector2.vector的用法    2.1vector的定义和声明    2.2成员函数        2.2.1基本函数            operator=            assign            get_allocator        2.2.2元素访问   ......
  • C++进制转换+扫描线算法(二维区间合并面积和)
    ......