移动语义 && 函数调用过程中的 lvalue
当以一个函数内的临时变量对象作为另一个函数的形参的时候,原函数内的临时对象即 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的更多相关文章
- ARM系统中函数调用过程中的参数传递-转
在 嵌入式软件编程中,经常会用到函数调用,之前在学习如何在C语言中嵌入汇编时有了解到C语言之前的参数调用是使用寄存器R0传递第一个参数,R1传递到第 二个..一直到R3传递第四个参数.但是实际上有时可 ...
- 函数调用过程中,函数参数的入栈顺序,why?
C语言函数参数入栈顺序为从右至左.具体原因为:C方式参数入栈顺序(从右至左)的好处就是可以动态变化参数个数.通过栈堆分析可知,自左向右的入栈方式,最前面的参数被压在栈底.除非知道参数个数,否则是无法通 ...
- 从一个新手容易混淆的例子简单分析C语言中函数调用过程
某天,王尼玛写了段C程序: #include <stdio.h> void input() { int i; ]; ; i < ; i++) { array[i] = i; } } ...
- 程序计数器(PC)、堆栈指针(SP)与函数调用过程
PC(program counter)是CPU中用于存放下一条指令地址的寄存器,SP为堆栈指针.下面将介绍函数调用过程中CPU对PC和SP这两个寄存器的操作. 假设有如下函数Fun Fun() { … ...
- C函数调用过程原理及函数栈帧分析(转)
在x86的计算机系统中,内存空间中的栈主要用于保存函数的参数,返回值,返回地址,本地变量等.一切的函数调用都要将不同的数据.地址压入或者弹出栈.因此,为了更好地理解函数的调用,我们需要先来看看栈是怎么 ...
- Linux内核源码阅读记录一之分析存储在不同段中的函数调用过程
在写驱动的过程中,对于入口函数与出口函数我们会用一句话来修饰他们:module_init与module_exit,那会什么经过修饰后,内核就能狗调用我们编写的入口函数与出口函数呢?下面就来分析内核调用 ...
- lua解析脚本过程中的关键数据结构介绍
在这一篇文章中我先来介绍一下lua解析一个脚本文件时要用到的一些关键的数据结构,为将来的一系列代码分析打下一个良好的基础.在整个过程中,比较重要的几个源码文件分别是:llex.h,lparse.h.l ...
- 从输入 URL 到浏览器接收的过程中发生了什么事情
从输入 URL 到浏览器接收的过程中发生了什么事情? 原文:http://www.codeceo.com/article/url-cpu-broswer.html 从触屏到 CPU 首先是「输入 U ...
- 百度自动发贴,登录很顺利的模拟实现,但发贴攻关失败,能力有限,追JS过程中颇为痛苦
攻关失败,且短期内看不到希望,看不到方向,且越来越焦急,目前已知的是,用根据用户的鼠标事件以一定的规则结合其他数据,服务器以这些数据验证是否为真正的手动发贴. 不过闲暇时实现了百度贴吧的自动签到. 较 ...
随机推荐
- 重构if...else...或者switch程序块
我们在开发asp.net时,经常有使用if...else...或者是使用switch来进行多个条件判断.如下面这篇<用户控件(UserControl) 使用事件 Ver2>http://w ...
- android sdk 镜像
大连东软信息学院镜像服务器地址:- http://mirrors.neusoft.edu.cn 端口:80北京化工大学镜像服务器地址:- IPv4: http://ubuntu.buct.edu.cn ...
- 三种对话框的示例(alert,confirm,prompt)
示例代码 <h2>JavaScriptDialog</h2> <hr/> <buttononclick="btn_alert()"> ...
- C#130问,初级程序员的面试宝典
首先介绍下,目前C#作为一门快速开发的语言,在面试的过程中需要注意的技术知识点,了解下面的知识点对于初级工程师入职非常有帮助,也是自己的亲身体悟. 1. 简述 private. protecte ...
- javascript:Bing Maps AJAX Control, Version 7.0
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 微软Asp.net MVC5生命周期流程图
.NET WEB Development blog 发布了Asp.net MVC5生命周期文档, 这个文档类似Asp.net应用程序生命周期,您以前开发ASP.NET WEB应用程序应该 ...
- 硅谷新闻4--解决页签手指按下从左到右滑动的bug
有一种方法可以阻止父层的View截获touch事件,就是调用 getParent().requestDisallowInterceptTouchEvent(true);方法.一旦底层View收到tou ...
- 最近提交并被合并的 jDiameter pull request 31 解决的问题
使用过程中发现的问题都提交并合并了,应该会出现在1.7.0版本中: https://github.com/RestComm/jdiameter/pull/31 修复多个超时事件同时发生的问题. 修复B ...
- 约瑟夫问题(c++实现)
描述:约瑟夫问题:有n只猴子,按顺时针方向围成一圈选大王(编号从1到n),从第1号开始报数,一直数到m,数到m的猴子退出圈外,剩下的猴子再接着从1 开始报数.就这样,直到圈内只剩下一只猴子时,这个猴子 ...
- javascript宿主对象之window.frames
window.frames属性是当前页面所有框架的集合.要注意的事,这里并没有frame和iframe做出区分.而且,无论页面存不存在框架,window.frames属性总是存在的,并总是指向wind ...