为什么下面的代码没有断言?

时间:2013-06-10 18:05:27

标签: c++ c++11 rvalue-reference

在comp.std.c ++上的

On this link,Howard Hinnant先生展示了以下代码:

#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);
}

然后他写道:

  

根据N1377规则,它没有断言。 ...

使用实际的C ++ 11规则,上面的代码无法编译,因为a中的左值main()未绑定到右值引用。但是,只是假设它被编译,正如本次讨论发生的情况可能应该这样,我无法理解上面的断言,即By the N1377 rules, it does not assert.。根据先前的规则,变量a不会被盗(a.data_ = 0),因为a作为参数传递给f f(a)?

1 个答案:

答案 0 :(得分:1)

在C ++ 0x标准中,&amp;&amp;声明专门提到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;

rvalue引用允许不涉及创建临时对象的惯用语,并使用50%以上的内存。尽管如此,即使按照我们关心A&amp; A之间差异的旧标准来说也是如此。和A&amp;&amp;,如果你编写合理的代码,使用rvalue引用dissapears,因为任何体面的编译器都可以在标准代码中轻松优化其优势。

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

编辑:根据评论。

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

所以,const A&amp;版本比A&amp;&amp;版。尽管const A&amp;是一种更简洁的类型匹配,A&amp;&amp;版本更快,并且使用它的危险对于左值的最后引用是不存在的。 Alexandrescu建议,对于这样的“最终参考”,我们使用rvalue。

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

Hinnants的例子表明,这是一个微观优化,规则需要比Alexandrescu建议更加明确。而且,因为我们也可以通过引用传递左值,你可以安全地使用这样的右值引用的时间,最终只有一次变量声明,最好是次要优化。