C++ 11加了许多新的功能。其中对C++性能和我们设计classconstructorassignment可能产生重大影响的非rvalue reference莫属!我看了不少资料,能说清它的不多。下面我企图用简单的例子来说明,希望读者能够理解并应用这一重要的语言构造。

1.rvalue reference 是reference (即指针)

比如下面两条语句的语义完全一样:

int &&p = 3;             // line 1

const int &cp = 3      // line 2

2. rvalue reference 指向临时变量

上面的line1line2的共同点是,他们都指向临时变量。所不同的是下面两句:

p = 5;       // p 的内容变成了5

cp = 5;      // 编译出错:cp 不能改动(常数)

3.rvalue reference可以简化moving 语义 – 提高object 拷贝性能

很好,我们现在可以通过rvalue reference修改(阴暗中的)临时变量了。那么这有什么用呢?目前C++11所宣称的最主要的应用就是所谓的“moving semantics (迁移语义)”。请看下面例子:

class SimpleString

{

       char * _ptr;

public:

       SimpleString(const char *p);

       SimpleString(const SimpleString & another);

       ~SimpleString();

       operator const char * () { return _ptr; }

       SimpleString & operator = (const SimpleString & another);

       static void Test();

private:

       void GetStr(const char *p);

};

SimpleString::SimpleString(const char *p): _ptr(nullptr)

{

       GetStr(p);

}

SimpleString::SimpleString(const SimpleString & another): _ptr(nullptr)

{

       GetStr(another._ptr);

}

void SimpleString::GetStr(const char *p)

{

       if (_ptr)

             delete [] _ptr;

 

       size_t l= ::strlen(p);

       _ptr = new char[l+1];

       ::strcpy_s(this->_ptr, l+1, p);

} 

SimpleString::~SimpleString()

{

       if (_ptr)

       {

             delete [] _ptr;

             printf("SimpleString d'tr called for \n");

       }

}

SimpleString & SimpleString::operator = ( const SimpleString & another)

{

       GetStr(another._ptr);

       return *this;

}

namespace

{

      // simple string factory

       SimpleString CreateString()

       {

             SimpleString temp("A temp string created!");

             return temp;

       }

} 

void SimpleString::Test()

{

       SimpleString ret = CreateString();

       printf("ret is: &s \n", ret);

}

上面是一个为了试验用的简单string class。 假设我们有一个函数CreateString, 返回一个创建的SimpleString 值。然后赋给接受变量ret。 这个简单的逻辑有什么问题呢?

这里就是临时变量copy constructor的问题。我们这里用了SimpleString::SimpleString(const SimpleString & another),它用GetStr来构建一个新的指针_ptr。然后将临时变量的_ptr所指内容拷贝过来。

这是常见的做法,但是很昂贵的。CreateString函数已经构建了一个有效的_ptr,为什不能拷贝指针呢?

原来,因为CreateString里的temp变量是临时变量,它在CreateString出口时将会被销毁,除非我们能获取他的referencepointer,然后将它的_ptr设为null。这是个好主意,我们再加一个函数:

void SimpleString::MoveStr(SimpleString & another)

{

       if (this->_ptr)

             delete this->_ptr;

 

       this->_ptr = another._ptr;

       another._ptr = nullptr;

}

然后把copy constructor 改写:

SimpleString::SimpleString(const SimpleString & another): _ptr(nullptr)

{

       MoveStr(const_cast<SimpleString &>(another)); // line 100

}

这样一来,我们就只构建一次_ptr了,测试的结果也证明了这一点。

上面讲的和rvalue reference有何关系呢?

我对line 100的方案不太满意:

1) 我们改变了原来copy constructor的常规意义,现在只要你赋值与另一变量,你就失去了你自己的值。我们希望这个功能只适合于“临时变量”。

2) const_cast 不太好,不美观。

现在,我们因该悟出rvalue reference的意义了吧?

根据第二节,rvalue reference是指向临时变量的,正好是用于指向CreateString产生的临时变量。

原来,只要我们在SimpleString里加一个moving copy constructor(注意&&):

SimpleString::SimpleString(SimpleString && another): _ptr(nullptr)

{

       MoveStr(another);

}

我们便无需更改SimpleString::SimpleString(const SimpleString & another)了。C++编译自动地在这一行SimpleString ret = CreateString() call 我们的moving constructor SimpleString::SimpleString(SimpleString && another), 而不是我们的copy constructor.

大家不妨试试!

总结

C++11利用rvalue reference,使我们可以方便地实现 moving constructor 语义。这对上述类似的问题(特别是std里的container用法)提供了解决C++传统的临时变量拷贝的功能隐患。

附录:修改后的代码

// header: RValueRef.h

class SimpleString

{

         char * _ptr;

public:

         SimpleString(const char *p);

         SimpleString(const SimpleString & another);

         SimpleString(SimpleString && another); // moving constructor

 

         ~SimpleString();

         operator const char * () { return _ptr; }

         SimpleString & operator = (const SimpleString & another);

         SimpleString & SimpleString::operator = ( SimpleString && another);

 

         static void Test();

 

private:

         void GetStr(const char *p);

         void MoveStr(SimpleString & another);

};

// C++: rvalue.cpp

#include "stdafx.h"

#include <string.h>

#include <stdlib.h>

#include <stdio.h>

#include <errno.h>

#include "RValueRef.h"

 

SimpleString::SimpleString(const char *p): _ptr(nullptr)

{

         GetStr(p);

}

 

SimpleString::SimpleString(const SimpleString & another): _ptr(nullptr)

{

         GetStr(another._ptr);

}

 

// Moving constructor helps move temp var’s _ptr to ourselves.

SimpleString::SimpleString(SimpleString && another): _ptr(nullptr)

{

         MoveStr(another);

}

void SimpleString::GetStr(const char *p)

{

         if (_ptr)

                 delete [] _ptr;

 

         size_t l= ::strlen(p);

         _ptr = new char[l+1];

         ::strcpy_s(this->_ptr, l+1, p);

}

SimpleString::~SimpleString()

{

         if (_ptr)

         {

                 printf("SimpleString d'tr called for '%s'\n", _ptr);

                 delete [] _ptr;

         }

}

SimpleString & SimpleString::operator = ( const SimpleString & another)

{

         GetStr(another._ptr);

         return *this;

}

SimpleString & SimpleString::operator = ( SimpleString && another)

{

         MoveStr(another);

         return *this;

}

void SimpleString::MoveStr(SimpleString & another)

{

         if (this->_ptr)

                 delete this->_ptr;

 

         this->_ptr = another._ptr;

         another._ptr = nullptr; // don’t forget to do this

}

namespace

{

          SimpleString CreateString()

         {

                 SimpleString temp("A temp string created!");

                 return temp;

         }

 

}

void SimpleString::Test()

{

         SimpleString ret = CreateString();

         printf("ret is: &s \n", ret);

}

二十分钟弄懂C++11 的 rvalue reference (C++ 性能剖析 (5))的更多相关文章

  1. 彻底弄懂LSH之simHash算法

    马克·吐温曾经说过,所谓经典小说,就是指很多人希望读过,但很少人真正花时间去读的小说.这种说法同样适用于“经典”的计算机书籍. 最近一直在看LSH,不过由于matlab基础比较差,一直没搞懂.最近看的 ...

  2. 必须弄懂的495个C语言问题

    1.1 我如何决定使用那种整数类型? 如果需要大数 值(大于32, 767 或小于¡32, 767), 使用long 型.否则, 如果空间很重要(如有大数组或很多结构), 使用short 型.除此之外 ...

  3. SQL Server-聚焦NOLOCK、UPDLOCK、HOLDLOCK、READPAST你弄懂多少?(三十四)

    前言 时间流逝比较快,博主也在快马加鞭学习SQL Server,下班回来再晚也不忘记更新下博客,时间挤挤总会有的,现在的努力求的是未来所谓的安稳,每学一门为的是深度而不是广度,求的是知识自成体系而不是 ...

  4. 一文弄懂神经网络中的反向传播法——BackPropagation【转】

    本文转载自:https://www.cnblogs.com/charlotte77/p/5629865.html 一文弄懂神经网络中的反向传播法——BackPropagation   最近在看深度学习 ...

  5. 这一次,彻底弄懂 JavaScript 执行机制

    本文转自https://juejin.im/post/59e85eebf265da430d571f89#heading-4 本文的目的就是要保证你彻底弄懂javascript的执行机制,如果读完本文还 ...

  6. 打工心态废掉了很多人,包括你吗?(你把现在这家公司的业务都弄清楚、弄懂了吗?君子报仇十年不晚!不离不弃!)good

    我只拿这点钱,凭什么去做那么多工作,我傻呀. 我为公司干活,公司付我一份报酬,等价交换而已,我不欠谁的. 我只要对得起这份薪水就行了,多一点我都不干,做了也白做. 工作嘛,又不是为自己干,说得过去就行 ...

  7. 彻底弄懂AngularJS中的transclusion

    点击查看AngularJS系列目录 彻底弄懂AngularJS中的transclusion AngularJS中指令的重要性是不言而喻的,指令让我们可以创建自己的HTML标记,它将自定义元素变成了一个 ...

  8. 彻底弄懂 JavaScript 执行机制

    本文的目的就是要保证你彻底弄懂javascript的执行机制,如果读完本文还不懂,可以揍我. 不论你是javascript新手还是老鸟,不论是面试求职,还是日常开发工作,我们经常会遇到这样的情况:给定 ...

  9. 彻底弄懂 Unicode 编码

    彻底弄懂 Unicode 编码 今天,在学习 Node.js 中的 Buffer 对象时,注意到它的 alloc 和 from 方法会默认用 UTF-8 编码,在数组中每位对应 1 字节的十六进制数. ...

随机推荐

  1. 7.DropDownList的绑定

    ListView中是无法像TextBox等控件那样将DropDownList的选中值绑定到数据字段的,必须编程处理.如例子:人员的性别(男,女,保密),三个值固定写在DropDownList中. 在显 ...

  2. Pearls DP

    Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 6647   Accepted: 3241 Description In Pe ...

  3. Codeforces Round #Pi (Div. 2) ABCDEF已更新

    A. Lineland Mail time limit per test 3 seconds memory limit per test 256 megabytes input standard in ...

  4. weblogic启动报错之未修改hosts产生错误

    报错如下: Enter username to boot WebLogic server:weblogic Enter password to boot WebLogic server: <Ju ...

  5. 【转】中兴G718C卡刷刷机教程(青漾2 4G)--不错

    原文网址:http://www.zterom.com/guide/2278.html 刷机包 B11纯净版 适合长久使用_B11_lite_0130.zip 刷机用了20多分钟. 在和大家分享过中兴G ...

  6. 【动态规划】Codeforces 711C Coloring Trees

    题目链接: http://codeforces.com/problemset/problem/711/C 题目大意: 给N棵树,M种颜色,已经有颜色的不能涂色,没颜色为0,可以涂色,每棵树I涂成颜色J ...

  7. [Locked] Zigzag Iterator

    Zigzag Iterator Given two 1d vectors, implement an iterator to return their elements alternately. Fo ...

  8. 理解Android的startservice和bindservice(转)

    一.首先,让我们确认下什么是service? service就是android系统中的服务,它有这么几个特点:它无法与用户直接进行交互.它必须由用户或者其他程序显式的启动.它的优先级比较高,它比处于前 ...

  9. A_star poj2449 k短路

    赛后填坑系列QAQ 贴代码呀 #include<iostream> #include<algorithm> #include<cstdio> #include< ...

  10. Structual设计--Flyweight模式

    1.意图 运用共享技术有效地支持大量细粒度的对象. 2.别名 无 3.动机 有些应用程序得意于在其整个设计过程中採用对象技术,但简单化的实现代价极大.如我们在使用word的时候.假设设置正文字体为:t ...