4

On this link on comp.std.c++, Mr. Howard Hinnant shows the following code:

#include <utility>
#include <cassert>

struct A
{
    A() : data_(1) {}
    A(A&& a) : data_(a.data_) {a.data_ = 0;}
    int data_;
};

void g(const A&) {}
void g(A&& a) {a.data_ = 0;}

void h(const A&) {}
void h(A&& a) {a.data_ = 0;}

void f(A&& a)
{
      g(a);  // calls g(const A&)
      h(a);  // calls h(const A&)
      if (true)
      {
          h(a); // calls h(A&&) (by Alexandrescu rules)
      }
}
int main()
{
    A a;
    f(a);
    assert(a.data_ == 1);
}

Then he writes:

By the N1377 rules, it does not assert. ...

With the actual C++11 rules the code above doesn't compile because the lvalue a in main() doesn't bind to an rvalue reference. But just assuming it compiled, as probably was supposed to the case when this discussion occurred, I can't understand the assertion above, that is, By the N1377 rules, it does not assert.. According to the prior rules, wouldn't the variable a be pilfered (a.data_ = 0), as a is passed as an argument to f with f(a) ?

4

1 回答 1

1

在 C++0x 标准中,&& 声明专门引用了 r 值引用。评论里的链接不错,还有这个链接,参考2006版。

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html

您还可以在此处找到有关该问题及其重要性的深入讨论:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html

简而言之,右值引用消除了对以下习语的需要:

int a = 10;
int b = 1000;

//Now let's swap them
int temp = a;
a = b;
b = temp;

右值引用允许不涉及创建临时对象的习惯用法,并使用 50% 以上的内存。虽然,即使在我们关心 A& 和 A&& 之间差异的旧标准上,如果您编写合理的代码,右值引用的使用就会消失,因为任何体面的编译器都可以在标准代码中轻松优化这些好处。

老实说,我不知道为什么 h(a) 调用更改为右值引用,因为它是在 if 语句的范围内调用的。

编辑:根据评论。

有人建议,在该变量范围内的变量的最终使用应默认为右值版本,因为这是更优化的,并且可能由这种引用引起的盗窃无关紧要,因为该变量很快就会超出范围。

因此, const A& 版本比 A&& 版本慢。尽管 const A& 是更简洁的类型匹配,但 A&& 版本更快,并且对于左值的最后引用不存在使用它的危险。Alexandrescu 提议,对于这样的“最终参考”,我们使用右值。

然而,Hinnant 声明(通过评论),在 Alexandrescu 建议的修改下,代码不会做预期的事情并抛出断言,但在当前的 n1377 规则下,使用标准绑定,它不会。揭穿他提议的标准变更。

Hinnants 示例表明这是一种微优化,并且该规则需要比 Alexandrescu 建议的更加简洁。而且,因为我们也可以通过引用传递左值,所以你可以安全地使用这种右值引用的时间,最终每次声明一个变量时只有一次,充其量只是一个小的优化。

于 2013-06-10T18:26:16.217 回答