右值引用与转移语义(C++11)
参考资料:
http://www.cnblogs.com/lebronjames/p/3614773.html
左值和右值定义:
C++( 包括 C) 中所有的表达式和变量要么是左值,要么是右值。通俗的左值的定义就是非临时对象(可以取地址,有名字),那些可以在多条语句中使用的对象。所有的变量都满足这个定义,在多条代码中都可以使用,都是左值。右值是指临时的对象,它们只在当前的语句中有效。请看下列示例 :
1. 简单的赋值语句
如:int i = 0;
在这条语句中,i 是左值,0 是临时值,就是右值。在下面的代码中,i 可以被引用,0 就不可以了。立即数都是右值。
2. 右值也可以出现在赋值表达式的左边,但是不能作为赋值的对象,因为右值只在当前语句有效,赋值没有意义。
如:((i>0) ? i : j) = 1;
在这个例子中,0 作为右值出现在了”=”的左边。但是赋值对象是 i 或者 j,都是左值。
在 C++11 之前,右值是不能被引用的,最大限度就是用常量引用绑定一个右值,如 :
const int &a = 1;
左值和右值的语法符号:
左值的声明符号为”&”, 为了和左值区分,右值的声明符号为”&&”。但是如果临时对象通过一个接受右值的函数传递给另一个函数时,就会变成左值,因为这个临时对象在传递过程中,变成了命名对象。
#include <iostream>
using namespace std; void value(int& v)
{
cout<<"left ";
cout<<__func__<<hex<<":"<<v<<endl;
} void value(int&& v)
{
cout<<"right ";
cout<<__func__<<hex<<":"<<v<<endl;
} void fvalue(int&& v)
{
value(v);
} int main()
{
int a=12;
value(a);
value(2);
fvalue(1); value(std::move(a));
}
转移语义:
右值引用是用来支持转移语义的。转移语义可以将资源 ( 堆,系统对象等 ) 从一个对象转移到另一个对象,这样能够减少不必要的临时对象的创建、拷贝以及销毁,能够大幅度提高 C++ 应用程序的性能。临时对象的维护 ( 创建和销毁 ) 对性能有严重影响。
通过转移语义,临时对象中的资源能够转移其它的对象里。
在现有的 C++ 机制中,我们可以定义拷贝构造函数和赋值函数。要实现转移语义,需要定义转移构造函数,还可以定义转移赋值操作符。对于右值的拷贝和赋值会调用转移构造函数和转移赋值操作符。如果转移构造函数和转移拷贝操作符没有定义,那么就遵循现有的机制,拷贝构造函数和赋值操作符会被调用。
示例:
#include <cassert>
#include <iostream>
#include <cstring> using namespace std; class String
{
private :
char *_data;
int _len; void init(const char* s)
{
_data=new char[_len+1];
memcpy(_data,s,_len);
_data[_len]='\0';
} public:
String():_data(nullptr),_len(0){}
String(const char* str)
{
assert(str!=nullptr);
_len=strlen(str);
init(str);
} String(const String& str)
{
cout<<"call cctor"<<endl;
_len=str._len;
init(str._data);
} String& operator=(const String& str)
{
cout<<"call copy assignment"<<endl;
if(this!=&str)
{
_len=str._len;
init(str._data);
}
return *this;
} //转移构造函数(C++11)
String(String&& str)
{
cout<<"call move ctor"<<endl;
_len=str._len;
_data=str._data;
str._data=nullptr;
str._len=0;
} //转移赋值操作符(C++11)
String& operator=(String&& str)
{
cout<<"call move assign"<<endl;
if(this!=&str)
{
_len=str._len;
_data=str._data;
}
return *this;
} void print()
{
cout<<"data:"<<hex<<_data<<endl;
} ~String()
{
cout<<"dctor"<<endl;
if(_data)
{
delete[] _data;
}
}
}; int main()
{
const char* s="hello world";
String str(s);
str.print(); String tmp(String("hello"));
tmp.print(); String&& mstr=std::move(str);
tmp=mstr;
tmp.print();
}
编译选项:g++ move.cpp -std=c++11 -fno-elide-constructors
其中-fno-elide-constructors 意思是:强制g++总是调用copy构造函数,即使在用临时对象初始化另一个同类型对象的时候。
标准库函数std::move
既然编译器只对右值引用才能调用转移构造函数和转移赋值函数,而所有命名对象都只能是左值引用,如果已知一个命名对象不再被使用而想对它调用转移构造函数和转移赋值函数,也就是把一个左值引用当做右值引用来使用,怎么做呢?标准库提供了函数 std::move,这个函数以非常简单的方式将左值引用转换为右值引用。
示例:
#include<iostream>
using namespace std; template<class T>
void m_swap(T& a,T& b)
{
T tmp(std::move(a));
a=std::move(b);
b=std::move(tmp);
} int main()
{
int a=0;
int b=1;
cout<<"before swap:"<<a<<" "<<b<<endl; m_swap(a,b);
cout<<"after swap:"<<a<<" "<<b<<endl;
}
右值引用与转移语义(C++11)的更多相关文章
- 【转】C++11 标准新特性: 右值引用与转移语义
VS2013出来了,对于C++来说,最大的改变莫过于对于C++11新特性的支持,在网上搜了一下C++11的介绍,发现这篇文章非常不错,分享给大家同时自己作为存档. 原文地址:http://www.ib ...
- C++11 标准新特性: 右值引用与转移语义
文章出处:https://www.ibm.com/developerworks/cn/aix/library/1307_lisl_c11/ 新特性的目的 右值引用 (Rvalue Referene) ...
- C++11 右值引用和转移语义
新特性的目的 右值引用 (Rvalue Referene) 是 C++ 新标准 (C++11, 11 代表 2011 年 ) 中引入的新特性 , 它实现了转移语义 (Move Sementics) 和 ...
- C++11 右值引用 与 转移语义
新特性的目的 右值引用(R-value Reference)是C++新标准(C++11, 11代表2011年)中引入的新特性,它实现了转移语义(Move Semantics)和精确传递(Perfect ...
- C++右值引用与转移语义
std::forwad? C++11 中定义的 T&& 的推导规则为: 右值实参为右值引用,左值实参仍然为左值引用. 参考: 右值引用与转移语义
- C++11新特性:右值引用和转移构造函数
问题背景 #include <iostream> using namespace std; vector<int> doubleValues (const vector< ...
- C++11新特性之右值引用(&&)、移动语义(move)、完美转换(forward)
1. 右值引用 个人认为右值引用的目的主要是为了是减少内存拷贝,优化性能. 比如下面的代码: String Fun() { String str = "hello world"; ...
- [c++11]右值引用、移动语义和完美转发
c++中引入了右值引用和移动语义,可以避免无谓的复制,提高程序性能.有点难理解,于是花时间整理一下自己的理解. 左值.右值 C++中所有的值都必然属于左值.右值二者之一.左值是指表达式结束后依然存在的 ...
- [转][c++11]我理解的右值引用、移动语义和完美转发
c++中引入了右值引用和移动语义,可以避免无谓的复制,提高程序性能.有点难理解,于是花时间整理一下自己的理解. 左值.右值 C++中所有的值都必然属于左值.右值二者之一.左值是指表达式结束后依然存在的 ...
随机推荐
- mysql中什么是逻辑备份
需求描述: mysql中,或者说关系型数据库中逻辑备份到底指的是什么呢,主要还是对于 概念的理解,在此记录下. 概念解释: 逻辑备份:主要指的是保存数据库的逻辑结构(比如:create dattaba ...
- 超全面的JavaWeb笔记day13<JSTL&自定义标签>
1.JSTL标签库(重点) core out set remove url if choose when otherwise forEach fmt formatDate formatNumber 2 ...
- ionic安装及测试
官方教程: http://ionicframework.com/getting-started/ 官方教程写得比较简单,简单来说就是 1)安装nodejs(安装方法:http://www.cnblog ...
- 调试寄存器 原理与使用:DR0-DR7
调试寄存器 原理与使用:DR0-DR7 下面介绍的知识性信息来自intel IA-32手册(可以在intel的开发手册或者官方网站查到),提示和补充来自学习调试器实现时的总结. 希望能给你带去有用的信 ...
- DAG 的最短路径算法
求图中节点的单源最短路径可以使用Dijkstra,BellmanFord, SPFA算法,而对于有向无环图DAG来说,可以通过简单的动态规划来进行求解. DAG的独特之处是所有节点可以线性化( ...
- LeetCode——Palindrome Linked List
Description: Given a singly linked list, determine if it is a palindrome. Follow up:Could you do it ...
- 几种减小javascript对性能影响的方法
1.将所有的script标签放在页面的底部,body的结束标签</body>之前. 2.将脚本打包,script标签越少,请求数就越少,加载速度加快,相应的响应时间变短. 3.使用非阻塞的 ...
- Html5 拖拽行为和AngularJs的结合
一. Html5的拖拽行为 1.设置元素为可拖放:把draggable属性设置为true. example: <div id="drag1" draggable=" ...
- java中得到文件MIME类型的几种方法(转)
本文转载自:http://hotsunshine.iteye.com/blog/857485 使用 javax.activation.MimetypesFileTypeMap 需要引入activat ...
- [SQL] sql server中如何查看执行效率不高的语句
sql server中,如果想知道有哪些语句是执行效率不高的,应该如何查看呢?下面就将为您介绍sql server中如何查看执行效率不高的语句,供您参考.在测量功能时,先以下命令清除sql serve ...