何时需要R值参考?

时间:2012-06-23 07:08:22

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

据我所知,如果没有R值引用,C ++中的完美转发是不可能的。

但是,我想知道:还有什么需要吗?


例如,this page指出了这个示例,其中显然需要R值引用:

  X foo();
  X x;
  // perhaps use x in various ways
  x = foo();
     

上一行:

     
      
  • 销毁x
  • 所持有的资源   
  • foo
  • 返回的临时值中克隆资源   
  • 销毁临时用户,从而释放其资源。
  •   

但是,在我看来,如果正确实施swap,那么简单的更改就可以解决问题:

X foo();
X x;
// perhaps use x in various ways
{
    X y = foo();
    swap(x, y);
}

所以在我看来,r值不会引用必要进行此优化。 (这是正确的吗?)

那么,有什么问题可以用r值引用解决(除了完全转发,我已经知道了)?

1 个答案:

答案 0 :(得分:12)

  

那么,r值引用无法解决的问题是什么(完全转发除外,我已经知道了)?

是。为了使swap技巧起作用(或者至少是最佳工作),必须将类设计为在构造时处于空状态。想象一下vector实现总是保留一些元素,而不是从完全空的开始。从具有已存在的vector的这种默认构造的vector交换将意味着进行额外的分配(在此vector实现的默认构造函数中)。

通过实际移动,默认构造的对象可以分配数据,但移动的对象可以保持未分配状态。

另外,请考虑以下代码:

std::unique_ptr<T> make_unique(...) {return std::unique_ptr<T>(new T(...));}

std::unique_ptr<T> unique = make_unique();

这是不可能没有语言级别的移动语义。为什么?因为第二个声明。按照标准,这是复制初始化。顾名思义,这需要类型 copyable unique_ptr的全部意义在于它是独一无二的。 IE:不可复制。

如果移动语义不存在,则无法返回。哦,是的,你可以谈论复制elision等,但请记住:elision是优化。符合标准的编译器仍必须检测到复制构造函数存在且可调用;编译器只能选择不调用它。

所以不,你不能只用swap来模拟移动语义。而且坦率地说,即使你可以,为什么你会想要

您必须自己编写swap个实现。因此,如果您有一个包含6个成员的课程,您的swap函数必须依次交换每个成员。递归遍历所有基类等。

C ++ 11(虽然不是VC10或VC2012)允许编译器为您编写移动构造函数

是的,有些情况下你可以在没有它的情况下离开。但他们看起来非常难以理解,很难理解为什么你这样做,最重要的是,让读者和作者都感到困难。

当人们为了性能而想要做很多事情时,会使他们的代码读取繁琐,难以编写和易于维护(在不将其添加到swap函数的情况下将其他成员添加到类中,例如),那么你正在寻找可能应该成为语言一部分的东西。特别是当编译器可以很容易地处理它时。