移动语义 && 函数调用过程中的 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过程中颇为痛苦
		
攻关失败,且短期内看不到希望,看不到方向,且越来越焦急,目前已知的是,用根据用户的鼠标事件以一定的规则结合其他数据,服务器以这些数据验证是否为真正的手动发贴. 不过闲暇时实现了百度贴吧的自动签到. 较 ...
 
随机推荐
- weblogic 12C 数据源配置出错的解决办法
			
驱动程序类名称: 11G 10.3.6与12G数据源配置有很大区别,整个一天才搞明白. 如有疑问可留言:http://www.cnblogs.com/endv/p/4110798.html 配 ...
 - 重新想象 Windows 8 Store Apps (55) - 绑定: MVVM 模式
			
[源码下载] 重新想象 Windows 8 Store Apps (55) - 绑定: MVVM 模式 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 绑定 通过 M ...
 - Fluent NHibernate example
			
http://www.codeproject.com/Articles/26466/Dependency-Injection-using-Spring-NET http://stackoverflow ...
 - MySQL SQL模式匹配
			
MySQL提供标准的SQL模式匹配,SQL模式匹配允许你使用“_”匹配任何单个字符,而“%”匹配任意数目字符(包括零字符).. 关于SQL模式匹配:http://dev.mysql.com/doc/r ...
 - 在一个未知的CentOS服务器中如何加上PHP的openssl扩展
			
1. 服务器是定制过的,不知对应的centos版本: 2. PHP是自己编译的,而且服务器上没有保留对应版本的源代码,通过/pathto/php -v 找出php版本号,然后wget去下载对应的php ...
 - window10 mysql5.7 解压版 安装
			
1. 解压mysql-5.7.11-winx64.zip 到某文件夹, 如C:\DevelopCommon\mysql-5.7.11-winx64. 2. 配置环境变量 变量名 : MYSQL_HOM ...
 - Tomcat配置文件server.xml
			
Tomcat目录中的server.xml配置文件 server.xml称为主配置文件或全局配置文件 它完成以下两个目标: 1,提供Tomcat组件的初始化配置 2,说明Tomcat的结构和含义,使得T ...
 - 两种设计模式(2)==>>"单例"
			
所谓“单例”: 单例模式是一种常用的软件设计模式.在它的核心结构中只包含一个被称为单例的特殊类.通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资 ...
 - mysql root强密码的必要性max_allowed_packet被改成1024引起的风险
			
前两天运维反馈说,有些机器的max_allowed_packet隔两天就会被改成1024,导致客户端调用时出错,网上有说内存不够的,也有人工修改的. 运维小姑娘一口咬定肯定没有改过的,而且my.cnf ...
 - ASP.NET MVC 微信公共平台开发之获取用户消息并处理
			
ASP.NET MVC 微信公共平台开发 获取用户消息并处理 获取用户消息 用户发送的消息是在微信服务器发送的一个HTTP POST请求中包含的,获取用户发送的消息要从POST请求的数据流中获取 微信 ...