移动构造函数及右值左值引用详解

Posted 卷起来卷起来

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了移动构造函数及右值左值引用详解相关的知识,希望对你有一定的参考价值。

1.移动构造函数:

  1. 有时候我们会遇到这样一种情况,我们用对象a初始化对象b后对象a我们就不在使用了,但是对象a的空间还在呀(在析构之前),既然拷贝构造函数,实际上就是把a对象的内容复制一份到b中,那么为什么我们不能直接使用a的空间呢?这样就避免了新的空间的分配,大大降低了构造的成本。这就是移动构造函数设计的初衷;
  2. 拷贝构造函数中,对于指针,我们一定要采用深拷贝,而移动构造函数中,对于指针,我们采用
    浅拷贝;
  3. 与拷贝类似,移动也使用一个对象的值设置另一个对象的值。但是,又与拷贝不同的是,移动实现的是对象值真实的转移(源对象到目的对象):源对象将丢失其内容,其内容将被目的对象占有。移动操作的发生的时候,是当移动值的对象是未命名的对象的时候。这里未命名的对象就是那些临时变量,甚至都不会有名称。典型的未命名对象就是函数的返回值或者类型转换的对象

使用移动构造函数和移动赋值:当使用一个临时变量对象进行构造初始化的时候,调用移动构造函数。类似的,使用未命名的变量的值赋给一个对象时,调用移动赋值操作;
代码如下:

Example6 (Example6&& x) : ptr(x.ptr) 
 {
 x.ptr = nullptr;
 }
 // move assignment
 Example6& operator= (Example6&& x) 
 {
 delete ptr; 
 ptr = x.ptr;
 x.ptr=nullptr;
 return *this;
}

2. 左值右值:

C++11正是通过引入右值引用来优化性能,具体来说是通过移动语义来避免无谓拷贝的问题,通过move语义来将临时生成的左值中的资源无代价的转移到另外一个对象中去,通过完美转发来解决不能按照参
数实际类型来转发的问题。
左值:表示的是可以获取地址的表达式,它能出现在赋值语句的左边,对该表达式进行赋值。可
以取地址的、有名字的就是左值。
右值:表示无法获取地址的对象,有常量值、函数返回值、lambda表达式等。无法获取地址,但不表示其不可改变,当定义了右值的右值引用时就可以更改右值。不能取地址的、没有名字的就是右值。

3. 左值右值引用:

左值引用:传统的C++中引用被称为左值引用
右值引用:C++11中增加了右值引用,右值引用关联到右值时,右值被存储到特定位置,右值引用指向
该特定位置,也就是说,右值虽然无法获取地址,但是右值引用是可以获取地址的,该地址表示临时对象的存储位置

举个例子:

#include <bits/stdc++.h>
using namespace std;
template<typename T>
void fun(T&& t)
{
 cout << t << endl;
}
int getInt()
{
 return 5;
}
int main() {
 
 int a = 10;
 int& b = a; //b是左值引用
 int& c = 10; //错误,c是左值不能使用右值初始化
 int&& d = 10; //正确,右值引用用右值初始化
 int&& e = a; //错误,e是右值引用不能使用左值初始化
 const int& f = a; //正确,左值常引用相当于是万能型,可以用左值或者右值初始化
 const int& g = 10;//正确,左值常引用相当于是万能型,可以用左值或者右值初始化
 const int&& h = 10; //正确,右值常引用
 const int& aa = h;//正确
 int& i = getInt(); //错误,i是左值引用不能使用临时变量(右值)初始化
 int&& j = getInt(); //正确,函数返回值是右值
 fun(10); //此时fun函数的参数t是右值
 fun(a); //此时fun函数的参数t是左值
 return 0;
}

以上是关于移动构造函数及右值左值引用详解的主要内容,如果未能解决你的问题,请参考以下文章

移动语义的一切

左值左值引用右值右值引用

C++左值左值引用右值右值引用

左值与右值引用 详解

C++11:左值右值左值引用右值引用

C++11:左值右值左值引用右值引用