【问题标题】:rValue use - c++ 11rValue 使用 - C++ 11
【发布时间】:2018-01-30 10:03:56
【问题描述】:

我正在通过他的创作者的书学习 c++,我知道 rValue 基本上是不能通过它的地址定义的,你想移动它而不是复制。

在本书的后面,Stroustrup 会给出一个 Points struct

的例子
struct Point{
  int x,y;
}

struct Points{
  vector<Point> elem;
  Points(Point p0){elem.push_back(p0)};
  ...
}

Point x2{ {100,200} }

所以我的问题基本上是为什么在构造函数中它不使用 rValue 来移动发送的值?

也许像:

struct Points{
  vector<Point> elem;
  Points(Point&& p0){elem.push_back(p0)};
  ...
}

这样做是否更合适/不太清楚?

问候

【问题讨论】:

  • 我们通常拼写为“rvalue”,全小写。
  • 能够传递左值 Point 对我来说似乎是合理的。
  • 请注意,第二个示例中的p0 是一个左值,这意味着elem.push_back(p0) 会复制它。如果这本书有任何好处,它会解释这一点。
  • 您对右值的定义有缺陷。 I'm so sorry。规则有点复杂。
  • 值得注意的是,Point 是一个非常简单的类型,仅由基本成员组成,没关系。

标签: c++ struct rvalue-reference


【解决方案1】:

当移动比复制便宜时,移动值特别有用。碰巧,复制int 非常便宜。您的 CPU 将一直这样做,因为它将值从内存加载到寄存器或寄存器之间。因此,对于int moving is the same as copying

你的Point 是两个整数,同样的逻辑仍然成立。但是vector&lt;Point&gt; 是另一回事。你会发现sizeof(Points) 是一个很小的数字。这是因为它不包括sizeof(Point)*elem.size(),这是一个在运行时可能会发生变化的数量。这就是移动变得有益的地方。移动该向量会移动sizeof(Point)*elem.size()

【讨论】:

  • 是的,对不起,这个例子很简单,所以你建议如果这个操作是在一个 100 000X for 循环中,它可能是使用右值 push_back 的最好方法,但是如果要移动的数据的大小是有限的最好的方法是复制?
  • @nodeover:“移动”的本质是你不关心源发生了什么。这意味着交换可以实现为副本、交换甚至混合(一些结构成员被复制,一些被交换)。所有这些操作都会导致目的地获得正确的价值。这就是为什么移动int 是通过复制完成的——交换它们更昂贵。这样做 100.000 次循环不会改变这一点。但是如果你有一个指向 50.000 个整数的指针和一个指向 60.000 个整数的指针,那么交换两个指针是迄今为止最快的操作。
【解决方案2】:

“它不使用 rValue”到底是什么意思?你的意思是p0 不是作为右值“发送”的,还是说对push_back 的调用不使用右值?

  1. Point&amp;&amp; p0 使用右值初始化 - 到目前为止一切顺利。
  2. push_back (p0) 复制一个左值,您可能想要做的是:push_back (std::move (p0))

您可以使用一个很好的助记符来区分左值和右值:

只要有一个对象的名称,它就是一个左值,只要一个 对象没有名称,它是一个右值。

例如: call_to_some_function (std::string {"Hi there"});,这里传递给函数的字符串没有名称,它是一个右值。这同样适用于所有临时工。

 void some_function (std::string&& what)
 {
       do_something_with (what); // <- what is an lvalue
       do_something_else (std::move (what)); // <- turned into rvalue
       const std::string& foo = get_some_foo_string ();
       do_something_else (std::move (foo)); // <- No rvalue here!
 }

【讨论】:

  • 我喜欢你的解释,很清楚。那么这是否意味着右值只能在变量范围内用作“右值”?
  • 我不明白这个问题——你可以在任何地方使用右值,只要右值有一个名称,尽管它变成了左值。您可以从左值创建右值,这就是 std::move 所做的(表示对象 t 可能从“移动” cppreference.com)。每当您想移动而不是复制时,请使用std::move,就像在您的第二个代码示例中一样,如果您编写push_back (std::move (p0)),这确实会移动而不是复制。您的第一个示例将复制然后移动,因为您按值获取参数。
猜你喜欢
  • 2014-04-15
  • 1970-01-01
  • 1970-01-01
  • 2016-05-03
  • 2011-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-31
相关资源
最近更新 更多