C++中什么时候用move,什么时候用forward?

调用它两的主要目的一般都是将左值类型强制转换为右值类型从而在初始化其它对象时可以调用右值引用构造函数,减少内存的拷贝;

两者主要的区别:

forward<>();
也即完美转发语句:意思是将一个传进函数的参数原封不动的传递出去(这里的原封不动指的是如果传进来之前为右值,那么就以右值传出去,如果传进来是左值,那么就以左值传出去),表现形式就是函数的形参声明为右值引用,该参数需要传递出去就要用forward();因为参数传进函数内部后,不管是左值还是右值在函数内部都有名字(即都是左值)这个时候需要用forward将左值转变为右值,那么为什么函数形参为左值引用就不需要了呢?
因为左值引用传进来还是左值引用,没必要再用forward在变换一下。

使用场景:函数形参为右值引用时(比如int&& a)
那么在函数里就要对a使用

forward<int >(a);

int&& club(int&& a)
{
	//int temp = 4;
	return std::forward<int>(a);//因为返回类型为引用,返回值不会创建一个零时对象也就不会调用构造函数
}
int main()
{
	cout<<club(4);
	return 0;
 
}

move();
其实就是一个强制类型转换,将左值类型转换为右值类型,主要目的就是方便调用右值类型的构造函数,和static_cast<>(),差不多类似的作用,用了move的对象对其它对象进行初始化时会调用右值引用构造函数也是转移构造函数,这个构造函数的作用就是将对象的内容直接给要初始化的对象,而不是拷贝一个过去。

细心的可能已经发现了,这里的move将左值类型强制转化为右值类型与forward在函数里将左值类型强制转化为右值类型是查不多的,只不过一个对象之前就是左值类型,一个之前是右值类型。

使用场景:需要右值的地方

如下面的右值初始化构造函数:两种都可以,但更推荐第二种

    ClassRoom(vector<string>&& theStudents)
    :students{std::move(theStudents)}
    {
        cout << " +";
    }
        ClassRoom(vector<string>&& theStudents)
    :students{std::forward<vector<string>>(theStudents)}
    {
        cout << " +";
    }

上面可能有点绕,不要急让我们往下看;

首先我们要明确一个概念:什么是左值?什么是右值?

c++11 中对 rvalue 作了明确的定义:

Things that are declared as rvalue reference can be lvalues or rvalues. The distinguishing criterion is: if it has a name, then it is an lvalue. Otherwise, it is an rvalue.

如果一个变量有名字,它就是 lvalue,否则,它就是 rvalue。

详细请看上一篇文章:
C++中的左值、右值和左值引用、右值引用相关问题

一.move()的原型代码

template
typename remove_reference::type&&
std::move(T&& a)
{
typedef typename remove_reference::type&& RvalRef;
return static_cast(a);
}

从这里就可以看到,它就是一个强制转换类型,无论是左值还是右值都被转化为右值类型;

move的真实含义

代码分析:
1.
在这里插入图片描述
上图在调用ClassRoom的右值引用构造函数时会调用students对象的右值引用构造函数,这里用move是因为初始化的是classroom里的成员变量,就像函数里的局部变量也是左值类型,这里也是同样的道理。

2.下面这个字符串值类型中的右值引用构造函数为什么,没有用move对变量进行初始化呢?

    String(String&& theString)
        :length{ theString.length }
        , buffer{ theString.buffer }
    {
		theString.buffer = nullptr;
    }

那是因为这里的初始化是达到了基本数据这个层级,move并没有移动内存这种作用,并不像很多博客中说的那样可以移动内存将原来的数据直接给了新的变量,它还是拷贝了函数,所以这里并没有用,只能是将指针给成了相同的。

3.下面这个就是一个普通函数,相当于这个函数要从外面传进一个变量,
传进来的变量是左值的,传进后的student也是左值的,但是我想要减少内存拷贝对这个Students类型的动态数组进行初始化,那么就需要用move将传进去的对象右值化,进而调用Students类的右值引用构造函数,从而减少内存的拷贝而初始化。
在这里插入图片描述

二.forworad<>()的原型代码

template
TYPE&& forward(typename remove_reference::type& arg)
{
return static_cast<TYPE&&>(arg);
}
template<class TYPE, class ARG>
TYPE* acquire_obj(ARG&& arg)
{
return new TYPE(forward(arg));
}

这个原型就是用模本的自动推导功能确定对象传进来之前的值类型,然后在将该类型的对象返回;
在这里插入图片描述
在这里插入图片描述

©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页