当以一个函数内的临时变量对象作为另一个函数的形参的时候,原函数内的临时对象即 rvalue,就会成为此函数内的 lvalue。

这样会重新导致效率低下,因为造成了大量复制操作。

<utility>头文件提供了 std:move()函数。此函数返回作为 rvalue 传递给的任何实参。

观察下面程序的输出:

class CText
{
private:
char *pText; public:
void showIt()const
{
cout << pText << endl;
} CText(const char* pStr = "No text")
{
cout << "CText constructor called" << endl;
size_t len{ strlen(pStr) + };
pText = new char[len];
strcpy_s(pText, len, pStr);
} CText(const CText & txt)
{
cout << "CText copy constructor called" << endl;
size_t len{ strlen(txt.pText) + };
pText = new char[len];
strcpy_s(pText, len, txt.pText);
} CText(CText && txt)
{
cout << "CText move constructor called" << endl;
pText = txt.pText;
txt.pText = nullptr;
} ~CText()
{
cout << "CText destructor called" << endl;
delete[]pText;
} CText & operator=(const CText & txt)
{
cout << "CText assignment operator function called" << endl;
if (this != &txt)
{
delete[]pText;
size_t length{ strlen(txt.pText) + };
pText = new char[length];
strcpy_s(pText, length, txt.pText);
}
return *this;
} CText & operator=(CText && txt)
{
cout << "CText move assignment operator function called" << endl;
delete[]pText;
pText = txt.pText;
txt.pText = nullptr;
return *this;
} CText operator+(const CText & txt)const
{
cout << "CText add operator function called" << endl;
size_t length{ strlen(pText) + strlen(txt.pText) + };
CText aText;
aText.pText = new char[length];
strcpy_s(aText.pText, length, pText);
strcat_s(aText.pText, length, txt.pText);
return aText;
}
};

CText 实现了移动语义的复制构造和赋值运算符函数,并且CText的对象作为CMessage类的成员。

class CMessage
{
private:
CText m_Text; public:
void showIt()const
{
m_Text.showIt();
} CMessage operator+(const CMessage & aMess) const
{
cout << "CMessage add operator function called" << endl;
CMessage message;
message.m_Text = m_Text + aMess.m_Text;
return message; } CMessage & operator=(const CMessage & aMess)
{
cout << "CMessage assignment operator function called" << endl;
if (this != &aMess)
{
m_Text = aMess.m_Text;
}
return *this;
} CMessage & operator=(CMessage && aMess)
{
cout << "CMessage move assignment operator function called" << endl;
m_Text = aMess.m_Text;
return *this;
} CMessage(const char * str = "Default message")//:m_Text{ str }//m_Text { CText(str) }
{
cout << "CMessage constructor called----" << endl;
m_Text = CText(str);
} CMessage(const CMessage & amess)
{
cout << "cmessage copy constructor called" << endl;
m_Text = amess.m_Text;
} CMessage(const CMessage && amess)
{
cout << "cmessage move constructor called" << endl;
m_Text = amess.m_Text;
}
}; int main()
{
CMessage motto1{"The devi1 takes care of his own.\n"}; cout << "----------------------------------------" << endl; CMessage motto2{"if yuo sup with the devil use a long spoon.\n"}; cout << "----------------------------------------" << endl; CMessage motto3{motto1+motto2}; cout << "----------------------------------------" << endl; motto3.showIt();
}

注意:CMessage 的构造函数,用初始化列表和在构造函数中初始化的差别。

当用初始化列表的输出如下:

:m_Text { CText(str) }
CText constructor called

CMessage constructor called
----------------------------------------
CText constructor called
CMessage constructor called
----------------------------------------
CMessage add operator function called
CText constructor called
CMessage constructor called
CText add operator function called
CText constructor called
CText move constructor called
CText destructor called
CText move assignment operator function called
CText destructor called
CText constructor called
cmessage copy constructor called
CText assignment operator function called
CText destructor called
----------------------------------------
The devi1 takes care of his own.
if yuo sup with the devil use a long spoon.
CText destructor called
CText destructor called
CText destructor called

用思维把运行过程走一遍,会发现红色部分出现问题(rvalue 被函数当成 lvalue 使用)。

也许你会疑惑临时变量的生成等操作,并没有输出,因为它们是编译器暗地做的工作。就像按值传递一样,我们也一无所知。

方法:

若想要避免我们所看到的红色标记问题,使用移动语义就可以 std:move() 。

  CMessage(const CMessage && amess)
   {
      cout << "cmessage move constructor called" << endl;
      m_Text = std::move(amess.m_Text);
   }

  CMessage & operator=(CMessage && aMess)
   {
      cout << "CMessage move assignment operator function called" << endl;
     //  m_Text = std::move(aMess.m_Text);
      m_Text = static_cast<CText &&>(aMess.m_Text); //和 std:move() 功能一样,属于强制转换
      return *this;
   }

问题再描述:

如果我们已经按如上方式做了努力,而 CMessage & operator=( const CMessage && aMess),使用了 const ,使用移动语义也是没了效果。

这属于 const 类型函数,调用 const 函数问题。

移动语义 && 函数调用过程中的 lvalue的更多相关文章

  1. ARM系统中函数调用过程中的参数传递-转

    在 嵌入式软件编程中,经常会用到函数调用,之前在学习如何在C语言中嵌入汇编时有了解到C语言之前的参数调用是使用寄存器R0传递第一个参数,R1传递到第 二个..一直到R3传递第四个参数.但是实际上有时可 ...

  2. 函数调用过程中,函数参数的入栈顺序,why?

    C语言函数参数入栈顺序为从右至左.具体原因为:C方式参数入栈顺序(从右至左)的好处就是可以动态变化参数个数.通过栈堆分析可知,自左向右的入栈方式,最前面的参数被压在栈底.除非知道参数个数,否则是无法通 ...

  3. 从一个新手容易混淆的例子简单分析C语言中函数调用过程

    某天,王尼玛写了段C程序: #include <stdio.h> void input() { int i; ]; ; i < ; i++) { array[i] = i; } } ...

  4. 程序计数器(PC)、堆栈指针(SP)与函数调用过程

    PC(program counter)是CPU中用于存放下一条指令地址的寄存器,SP为堆栈指针.下面将介绍函数调用过程中CPU对PC和SP这两个寄存器的操作. 假设有如下函数Fun Fun() { … ...

  5. C函数调用过程原理及函数栈帧分析(转)

    在x86的计算机系统中,内存空间中的栈主要用于保存函数的参数,返回值,返回地址,本地变量等.一切的函数调用都要将不同的数据.地址压入或者弹出栈.因此,为了更好地理解函数的调用,我们需要先来看看栈是怎么 ...

  6. Linux内核源码阅读记录一之分析存储在不同段中的函数调用过程

    在写驱动的过程中,对于入口函数与出口函数我们会用一句话来修饰他们:module_init与module_exit,那会什么经过修饰后,内核就能狗调用我们编写的入口函数与出口函数呢?下面就来分析内核调用 ...

  7. lua解析脚本过程中的关键数据结构介绍

    在这一篇文章中我先来介绍一下lua解析一个脚本文件时要用到的一些关键的数据结构,为将来的一系列代码分析打下一个良好的基础.在整个过程中,比较重要的几个源码文件分别是:llex.h,lparse.h.l ...

  8. 从输入 URL 到浏览器接收的过程中发生了什么事情

    从输入 URL 到浏览器接收的过程中发生了什么事情? 原文:http://www.codeceo.com/article/url-cpu-broswer.html 从触屏到 CPU  首先是「输入 U ...

  9. 百度自动发贴,登录很顺利的模拟实现,但发贴攻关失败,能力有限,追JS过程中颇为痛苦

    攻关失败,且短期内看不到希望,看不到方向,且越来越焦急,目前已知的是,用根据用户的鼠标事件以一定的规则结合其他数据,服务器以这些数据验证是否为真正的手动发贴. 不过闲暇时实现了百度贴吧的自动签到. 较 ...

随机推荐

  1. 数论 - 素数的运用 --- poj 2689 : Prime Distance

    Prime Distance Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 12512   Accepted: 3340 D ...

  2. Python入门笔记(25):Python面向对象(2)

    一.类 类就是一个数据结构,封装了数据和操作. 类的声明与函数的声明十分类似: class newClass(object): """class documentatio ...

  3. csharp: InvokeHelper

    Entity Framework https://entityframework.codeplex.com/ Enterprise Library https://entlib.codeplex.co ...

  4. sql 大数据库 插入超时问题解决

    解决的办法:1. 不要使用自动收缩, 自动收缩会定期收容数据文件的空闲空间,则处理需要的时候却要扩大数据文件,这两者相反的处理,是冲突的设置方法:ALTER DATABASE MyDataBase S ...

  5. ajax案例源码

    html文件中demo2_index.html ---------------------------------------------------------------------------- ...

  6. Hibernate中的一对一关联和组件的映射

    Hibernate提供了两种映射一对一映射关联关系的方式: 01.按照外键映射 02.按照主键映射 下面以员工账号表和员工档案表(员工账号和档案表之间是一对一的关系)为例,介绍这两种映射关系,并使用这 ...

  7. Orchard MySql 修正版 下载

    Orchard是支持多种数据库的如果是个人站长推荐使用MySql作为运行数据库,虽然SqlServer更为强大,但总觉得SqlServer好重啊,一装就是几个G. 最近的版本在使用MySql建库时却会 ...

  8. SharpGL学习笔记(十六) 多重纹理映射

    多重纹理就把多张贴图隔和在一起.比如下面示例中,一个表现砖墙的纹理,配合一个表现聚光灯效果的灰度图,就形成了砖墙被一个聚光灯照亮的效果,这便是所谓的光照贴图技术. 多重纹理只在OpenGL扩展库中才提 ...

  9. C++之函数重载

    函数重载定义: 如果同一作用域内的几个函数名字相同但形参列表不同; 重载与const形参: Record (Phone); = Record(const Phone); Record(Phone*) ...

  10. 用js枚举实现简易菜单效果

    用js枚举实现简易菜单效果,左侧显示菜单,右侧显示用户选择的菜单,一图胜千言,还是直接来张效果图吧: 以下是代码: <DOCTYPE html> <html> <head ...