移动语义 && 函数调用过程中的 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过程中颇为痛苦
攻关失败,且短期内看不到希望,看不到方向,且越来越焦急,目前已知的是,用根据用户的鼠标事件以一定的规则结合其他数据,服务器以这些数据验证是否为真正的手动发贴. 不过闲暇时实现了百度贴吧的自动签到. 较 ...
随机推荐
- C#版本的历史
+ 展开目录 - 版本号的一些命名规则 - 语言,运行时,类库,开发工具的区 - 2002年 C#1.0发布 - 2005年 C#2.0发布 - 2007年 C#3.0发布 - 2010年 C#4.0 ...
- php中的字符串常用函数(四) ord() 获得字符的ascii码 chr()获取ascii码对应的字符
ord('a');//=>97 返回小写a 的ascii码值97 chr(97);//=>a 返回ascii码表上的97对应的 小写a
- java多线程(三)——锁机制synchronized(同步语句块)
用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法之行一个长时间的任务,那么B线程必须等待比较长的时间,在这样的情况下可以使用synchronized同步语句快来解 ...
- Docker on CentOS for beginners
Introduction The article will introduce Docker on CentOS. Key concepts Docker Docker is the world's ...
- 重载赋值运算符 && 对象
class CMessage { private: char * m_pMessage; public: void showIt()const { cout << m_pMessage & ...
- netty Failed to submit an exceptionCaught() event异常
最近测试netty开发的服务端应用在关闭时,出现下列异常: ->###WARN#########nioEventLoopGroup-3-2###io.netty.util.internal.lo ...
- DigitalOcean上SSH Key的创建(附DigitalOcean邀请)
DigitalOcean是一家云主机商家,最低配置512M内存,20G的SSD,每月只有5刀.半个月前刚刚在这上面买了一个VPS,创建Droplet的时候看见创建SSH Key的时候就有点懵,不知道这 ...
- OS X 在Cisco无线环境下丢包分析 part 1
补发一篇博客,之前遇到的没有写成博文的一个情况.我擦,那一阵儿真是被无线搞疯了. 现象:苹果OS X用户连入WiFi之后莫名丢包,而且有规律的丢,丢个5s恢复正常,再过会儿再丢5s左右. 就如同这样 ...
- MongoDB整合Spring
1.环境 Jdk:1.6.0_10-rc2 Spring3.1.2 下载 依赖jar文件: 2.相关配置 ①.Spring配置文件 <?xml version="1.0" ...
- MUI - 将tap模拟成原生click体验
mui提供了tap事件替换了html5的click事件,解决了300ms延时的问题.不过相比原生app的click体验还是有些许差距的.关于300ms延时的问题,这篇帖子分析的比较完善,其中提到了穿透 ...