C++ 新特性学习(七) — 右值引用

C++在效率上有个硬伤。我们知道C#和Java对于类传递都是以引用的方式,而C++默认都是传值。在传值过程中就经常会进行复制构造,这完全没必要而且浪费CPU,为了解决这种问题,于是乎C++11 增加了一个新的非常数引用(reference)类型,称为右值引用(R-value reference)。我就专门看了一下关于右值引用的东西。 右值引用在GCC 4.3之后开始支持,VS 2010(VC 10.0)已经支持,再前一点的VC版本没试过所以不知道。 右值引用的申明标记为T &&,主要用于处理临时变量,比如函数返回的变量(暂时想不出其他例子,忽略返回值优化吧,(命名)返回值优化参见http://efnetcpp.org/wiki/Return_value_optimization,再说返回值优化能力有限是吧,比要求如单返回语句、不能使用异常等等),避免复制构造。同时在析构的时候就不会析构这个临时变量,从而提升效率。 上代码:

class foo {
public:
    int m;
    foo(){ puts("directly"); }
    foo(const foo&){ puts("copy"); }
    foo(int i){ puts("int"); m = i; }
};

foo foo_func1(int flag)
{
    if(flag == 1)
        return foo();
    if(flag == 2)
        return foo(1);

    // 此处返回值优化就是个渣渣
    foo retv;
    return retv;
}

foo&& foo_func2(int flag)
{
    if(flag == 1)
        return foo();
    if(flag == 2)
        return foo(1);

    // 返回值优化就这么跪了
    foo retv;
    return std::move(retv);
}

foo rr1 = foo_func1(0); // 1
foo&& rr2 = foo_func2(0); // 2

对于1,如果没有右值引用,首先rr1调用foo的复制构造函数,然后析构返回的fs对象。 对于2,有右值引用,返回的foo对象直接传给rr2,少了一步复制构造和释放foo对象的操作。

基本原理就是这样,经实测,右值引用在字符串操作上可以带来近30%的效率提升。

另外,介绍两个和右值引用相关的函数

std::move 提取右值引用

template<class _Ty> inline
    typename _Ty &&
        move(_Ty&& _Arg) _NOEXCEPT
    {   // forward _Arg as movable
        return ((typename _Ty &&)_Arg);
    }

这个函数用于显示告诉编译器,我要拿到右值,很多情况下函数有重载的时候,会优先使用传值的形式,使用这个函数可以指定取回右值引用,这样可以阻止临时对象的析构和复制构造

std:: forward 引用参数转发

template<class _Ty> inline
_Ty&& forward(typename remove_reference<_Ty>::type& _Arg) { // forward an lvalue
    return (static_cast<_Ty&&>(_Arg));
}

template<class _Ty> inline
_Ty&& forward(typename remove_reference<_Ty>::type&& _Arg) _NOEXCEPT {  // forward anything
    static_assert(!is_lvalue_reference<_Ty>::value, "bad forward call");
    return (static_cast<_Ty&&>(_Arg));
}

// 其中移除引用的代码如下
// TEMPLATE remove_reference
template<class _Ty>
struct remove_reference { // remove reference
    typedef _Ty type;
};

template<class _Ty>
struct remove_reference<_Ty&> { // remove reference
    typedef _Ty type;
};

template<class _Ty>
struct remove_reference<_Ty&&> { // remove rvalue reference
    typedef _Ty type;
};

很多情况下,我们会直使用模板进行操作,当_Ty为左值引用类型时,u将被转换为_Ty类型的左值,否则u将被转换为_Ty类型右值,据说是拿来做保留左右值属性的完美转发的。

所谓完美转发(详见提案N1385),就是模板函数接收到什么类型,就转发给其调用的函数什么类型,详见:http://blog.csdn.net/pongba/article/details/1697636

漫漫长路,下一站,原子操作和多进程编程

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏TungHsu

这或许是对小白最友好的python入门了吧——3,数字处理

昨天那篇推文是不是太长了,以后为了大家能够更好地理解,所以我们还是写的少点,大家看完以后要好好练习哦! 不要在此处直接复制代码! 在Python中可以执行对整...

32960
来自专栏IT派

JavaScript 打怪升级 —— 把业务逻辑当练习题做

开发项目和出没社区有一段时间了,会遇上一些比较有印象业务需求。这些业务需求,可能是自己开发项目遇上的,可能是在社区看到的业务需求,或者其他情况接触到的需求,但是...

9130
来自专栏小俊博客

Nginx的location规则迷之匹配

Nginx,一个改变世界的软件,其作者是一个俄罗斯人,俗称毛子,在国人的印象中,是一群晚饭后牵着大灰熊在小区楼下散步的彪汉。能写出这般顺滑的软件,可谓是心有猛虎...

77520
来自专栏微信公众号:Java团长

探秘Java中的String、StringBuilder以及StringBuffer

  相信String这个类是Java中使用得最频繁的类之一,并且又是各大公司面试喜欢问到的地方,今天就来和大家一起学习一下String、StringBuilde...

9020
来自专栏Java架构沉思录

你真的懂Java中的String、StringBuilder和StringBuffer吗?

相信String这个类是Java中使用得最频繁的类之一,并且又是各大公司面试喜欢问到的地方,今天就来和大家一起学习一下String、StringBui...

19230
来自专栏深度学习之tensorflow实战篇

Python中的__init__()方法整理中(两种解释)

解释一:看懂了就不用看第二种了 __init__()方法是Python学习当中重要的基础知识,__init__()方法意义重大的原因有两个。第一个原因是在对...

1.2K60
来自专栏java一日一条

10行Java代码实现最近被使用(LRU)缓存

在最近的面试中,我曾被多次问到,怎么实现一个最近最少使用(LRU)的缓存。缓存可以通过哈希表来实现,然而为这个缓存增加大小限制会变成另一个有意思的问题。现在我们...

11620
来自专栏zingpLiu

python基础(一)

  python的创始人为吉多·范罗苏姆(Guido van Rossum)。1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚...

33820
来自专栏Java爬坑系列

【Java入门提高篇】Day1 抽象类

  基础部分内容差不多讲解完了,今天开始进入Java提高篇部分,这部分内容会比之前的内容复杂很多,希望大家做好心理准备,看不懂的部分可以多看两遍,仍不理解的部分...

24260
来自专栏linux驱动个人学习

Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析【转】

Android系统的运行时库层代码是用C++来编写的,用C++ 来写代码最容易出错的地方就是指针了,一旦使用不当,轻则造成内存泄漏,重则造成系统崩溃。不过系统为...

13120

扫码关注云+社区

领取腾讯云代金券