C&C++   发布时间:2022-04-01  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了c11 move 和 forward大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

c++11 : move forWARD

右值

如果一个数你可以获取他的地址那么他就是左值,否则为右值。给定一个类型T,他可以是左值的类型,也可以是右值的类型。@R_457_7369@。需要记住的是当处理右值引用类型的时候,他的参数本身是个左值。右值代表了这个对象可以进行move操作。

void f(Widget&& w);
class Widget{
  public :
  Widget(Widget&& rhs); // rhs is an lvalue,though it has a rvalue reference type
};

上面函数的参数w是一个lvalue,即使它的类型是右值引用类型。在类Widget的move构造函数的参数rhs的地址是可以获取到的,所以rhs是一个左值,然他是右值引用类型。

arguments与 parameters

parameter是指函数定义中参数,而Argument指的是函数调用时的实际参数。

void someFunc(Widget w); //parameter w is passed by value
Widget wid;
someFunc(wid); // w is a copy of wid that's created via copy construction
someFunc(std::move(wid)); // w is a copy of wid that's created via move construction

当使用另一个对象初始化一个对象的时候,新的对象是初始化对象的copy,即使这个copy是通过move constructor完成的。右值的copy是通过move constructor进行的,左值的copy是通过copy constructor进行的。

在上面的someFunc两次函数调用中,parameter是w,paramter是左值,而Argument可能是被左值或者右值初始化。

右值引用(rvale references)和全局引用(universal references)的区别:

T&&”有两种意思:

1.代表的是右值引用(rvalue referencE)。就是他绑定到一个右值上,代表对象的移动来源。

2.代表可能是右值引用也可能是左值引用。叫做全局引用。

全局引用使用在两个地方:

1.函数模板:

  template<typename T> void f(T&& param)   //param is a universal reference

2.auto 的使用:

 auto&& var2 = var1;

使用右值引用(T&& 第一种意思)的情况:

void f(Widget&& param)  // no type deduction param is an  rvalue reference
Widget&& var1 = Widget(); // no type deduction param is an  rvalue reference

特殊情况:

  1. 然T需要类型推理,但是param是vector不是"T&&"
template<typename T>
void f(std::vector<T>&& param) // param is an rvalue reference
  1. 对与const关键字:
template <typename T>
void f(const T&& param);  //param is an rvalue reference

std::move使用在rvalue reference std::forWARD使用在universal reference


class Widget{
  Wdiget(Widget&& rhs);//rhs definitely refers to an object eligible for moving
};

很严重的错误是将std::move应用到universal reference:会造成修改左值这样不愿意看到的错误:

class Widget{
  pulibc:
    templtea <typename T>
    void setName(T&& newName) //universal reference
    {
      name = std::move(newName); //compiles ,but is bad bad bad
    }
    ...
  private:
    std::string name;
}

std::string getWidgetName();

Widget w;
auto n = getWidgetName(); // moves n into w!
w.setName(n);    //n's value now unkonow;

这样最后n的值变成不确定状态了。也许是觉得使用两个函数重载:

class Widget{
public:
    void setName(const std::string& newName){name = newName;}
    void set(std::string&& newName) {name = std::move(newName);}
}

这种情况也是可以的。但是有缺点是这中方式不是很有效。会有很多std::string 的构造函数,析构函数,复制构造函数的调用过程。同时会增加代码量。还有一个更严重的问题是代码设计问题。现在只是一个参数就需要连个函数,如果函数接收参数过多,这样会需要跟多的重载函数。

如果你的函数返回值,你返回对象绑定到右值引用或者全局引用,你可以使用std::move或者std::forWARD返回这个引用:

@H_936_9@matrix operator+(Matrix&& lhs,const Matrix&rhs)
{
  lhs += rhs;
  return std::move(lhs); //move lhs into return value
}

Matrix operator+(Matrix&& lhs,const Matrix&rhs)
{
  lhs += rhs;
  return lhs;   //copy lhs into return value
}

如果Matrix支持move操作,则第一种比第二种情况要好,如果此时matrix不支持move操作也不会引起什么问题。因为右值会被Matrix的拷贝构造函数复制,如果后面Matrix支持了move操作则后面会自动转为第一种获益情况。

这种情况和std::forWARD的全局引用一样:

template<typename T>
Fraction reduceAndCopy(T&& fraC) //universal reference param
{
  frac.reduce();
  return std::forWARD<T>(frac); //move rvalue into return value,copy lvalue
}

则如果frace是右值则会movE into返回值中,如果是左值则复制。如果我们去掉std::forWARD则会无条件(不分左右值)的复制。

对应std::move 和 std::forWARD的理解:


std::move
在cpp上介绍: Returns an rvalue reference to arg.

和std::forWARD只是一个函数,该函数进行cast操作。move是无条件的转换为右值,而forWARD是有条件的转换。

当然,右值只是作为一个moving的候选

class Annotation{
  public :
    explicit Annotation(const std::string text):
        value(std::move(text))  // "move "text into value,this code doesn't do what it seems to!!
        {...}
  private:
      std::string value;
}

"text"并没有被moved into value,而是被复制。然text被move转为了右值,但是text被声明为const std::string,转化为const std::string的右值,但是:

class String{
public:
  ...
  String (const String&rhs); //copy ctor
  String (String&& rhs); //move ctor
}

const std::string右值无法作为std::string 的move 构造函数。不过可以作为拷贝构造函数参数。因为lvalue-reference-to-const是运行邦迪哦那个到const rvalue。

所以得出两条结论:

  • 不要将一个对像设置为const,如果你希望该从对象moving。
  • std::move 并不移动任何东西,而去也不保证被cast的东西真正被moved。唯一确定的是std::move把他转换为右值。

std::forWARD是有条件的转换:只有当参数是右值的时候才被转换为右值。

大佬总结

以上是大佬教程为你收集整理的c11 move 和 forward全部内容,希望文章能够帮你解决c11 move 和 forward所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: