c++11新特性:通过使用rvalue引用 引入 move semantic 和 perfect forwarding

在c++11标准中,一个显著的特点是引入了move semantic 和 perfect forwarding,这个新特性并非简单的“语法糖”,使用得当,可以带来程序性能的显著增强。

理解这两个概念,就必须要涉及到lvalue和rvalue,那么,我们就从lvalue和rvalue说起。在c语言的历史上,lvalue是left value的缩写,因为它可能出现在赋值表达式的左边,rvalue同理。c++继承了这样一个历史表达习惯,因此也引入了lvalue和rvalue,但是随着c++语言的发展,“left”和“right”已经变得不再准确,其中一个原因便是,我们在很多不是赋值表达式的地方也开始大量使用这两个概念,因此我们现在只认为l和r是两个不带字面意义的前缀。

实际上,WG21(ISO/IEC  JTC1/SC22/WG21)的Core subgroup主席William M. Miller,甚至在2010年提交了一篇专门关于名为《A Taxonomy of Expression Value Categories》[1]的提议,他想把表达式的值这样分类:


在这篇20页的论文中,他反复谈的就是这个问题,如果有兴趣可以去看这篇文章[1]。但是估计这个分类把人搞得很晕,所以这个论文似乎没有流行起来。

那么,如果我们不能通过左右来区分lvalue和rvalue,又应该怎样识别它们呢?其实可以问这样一个问题,“能否取得这个值的地址”,如果能,那么就是一个lvalue,反之就是一个rvalue。比如 &obj , &*ptr , &ptr[index] , and &++x 都是合法的,而 &1729 , &(x + y) , &std::string("meow") , and &x++ 都是非法的。微软VC++ 开发人员Stephan T. Lavavej  写了一篇很好的、很深刻的也很长的关于这个主题的文章《Rvalue References: C++0x Features in VC10》,如果要更详细的了解大量细节,可以精读此文[2]。

在简要介绍了lvalue和rvalue之后,就该进入正题了。在Howard E. Hinnant等提交的《A Proposal to Add an Rvalue Reference to the C++ Language》[3]中,他指出在C++中加入这个新特性有三个目的:

(1)消除针对用户定义类型的copy带来的巨大开销(move);

(2)解决通用的转发工具的易用性问题(forward);

(3)一个N1377提议中的错误(可忽略)。

针对上面两个(不包括3)如何被解决,Howard E. Hinnant等写了一篇名为《A Brief Introduction to Rvalue References》的文章[4],合作作者甚至包括了Bjarne Stroustrup。在该文章介绍了关于move 和 forwar的基本用法,和相比传统方法带来的优势。下面是关于move和forward在cplusplus.com上的例子:

// move example
#include <utility>      // std::move
#include <iostream>     // std::cout
#include <vector>       // std::vector
#include <string>       // std::string

int main () {
  std::string foo = "foo-string";
  std::string bar = "bar-string";
  std::vector<std::string> myvector;

  myvector.push_back (foo);                    // copies
  myvector.push_back (std::move(bar));         // moves

  std::cout << "myvector contains:";
  for (std::string& x:myvector) std::cout << ' ' << x;
  std::cout << '\n';

  return 0;
}

Output:

myvector contains: foo-string bar-string


// forward example
#include <utility>      // std::forward
#include <iostream>     // std::cout


// function with lvalue and rvalue reference overloads:
void overloaded (const int& x) {std::cout << "[lvalue]";}
void overloaded (int&& x) {std::cout << "[rvalue]";}


// function template taking rvalue reference to deduced type:
template <class T> void fn (T&& x) {
  overloaded (x);                   // always an lvalue
  overloaded (std::forward<T>(x));  // rvalue if argument is rvalue
}


int main () {
  int a;

  std::cout << "calling fn with lvalue: ";
  fn (a);
  std::cout << '\n';

  std::cout << "calling fn with rvalue: ";
  fn (0);
  std::cout << '\n';

  return 0;
}


Output:
calling fn with lvalue: [lvalue][lvalue]
calling fn with rvalue: [lvalue][rvalue]


 

参考文献:

[1] A Taxonomy of Expression Value Categories, http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3055.pdf

[2] Rvalue References: C++0x Features in VC10, http://blogs.msdn.com/b/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx

[3] A Proposal to Add an Rvalue Reference to the C++ Language, http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html

[4] A Brief Introduction to Rvalue References, http://www.artima.com/cppsource/rvalue.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值