参考资料:

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)的更多相关文章

  1. 【转】C++11 标准新特性: 右值引用与转移语义

    VS2013出来了,对于C++来说,最大的改变莫过于对于C++11新特性的支持,在网上搜了一下C++11的介绍,发现这篇文章非常不错,分享给大家同时自己作为存档. 原文地址:http://www.ib ...

  2. C++11 标准新特性: 右值引用与转移语义

    文章出处:https://www.ibm.com/developerworks/cn/aix/library/1307_lisl_c11/ 新特性的目的 右值引用 (Rvalue Referene) ...

  3. C++11 右值引用和转移语义

    新特性的目的 右值引用 (Rvalue Referene) 是 C++ 新标准 (C++11, 11 代表 2011 年 ) 中引入的新特性 , 它实现了转移语义 (Move Sementics) 和 ...

  4. C++11 右值引用 与 转移语义

    新特性的目的 右值引用(R-value Reference)是C++新标准(C++11, 11代表2011年)中引入的新特性,它实现了转移语义(Move Semantics)和精确传递(Perfect ...

  5. C++右值引用与转移语义

    std::forwad? C++11 中定义的 T&& 的推导规则为: 右值实参为右值引用,左值实参仍然为左值引用. 参考: 右值引用与转移语义

  6. C++11新特性:右值引用和转移构造函数

    问题背景 #include <iostream> using namespace std; vector<int> doubleValues (const vector< ...

  7. C++11新特性之右值引用(&&)、移动语义(move)、完美转换(forward)

    1. 右值引用 个人认为右值引用的目的主要是为了是减少内存拷贝,优化性能. 比如下面的代码: String Fun() { String str = "hello world"; ...

  8. [c++11]右值引用、移动语义和完美转发

    c++中引入了右值引用和移动语义,可以避免无谓的复制,提高程序性能.有点难理解,于是花时间整理一下自己的理解. 左值.右值 C++中所有的值都必然属于左值.右值二者之一.左值是指表达式结束后依然存在的 ...

  9. [转][c++11]我理解的右值引用、移动语义和完美转发

    c++中引入了右值引用和移动语义,可以避免无谓的复制,提高程序性能.有点难理解,于是花时间整理一下自己的理解. 左值.右值 C++中所有的值都必然属于左值.右值二者之一.左值是指表达式结束后依然存在的 ...

随机推荐

  1. 记录下一个自己不常用的关键字-yield

    yield 这个关键字 一直很少用,也不知道具体用途.按照习惯就查询了下MSDN. 意思大致是这样的:在迭代器块中用于向枚举数对象提供值或发出迭代结束信号 表现形式:1. yield return & ...

  2. python2.0_s12_day11_SqlAlchemy使用介绍

    SqlAlchemy ORM ORM的解释; 简单点:对象关系映射. 需求:我们写一个主机管理,把主机信息存在数据库,一开始我们编程不熟练的时候,执行命令时候要调用数据库,会把相应的SQL语句写到代码 ...

  3. 用命令行执行ROBOT FRAMEWORK用例

    转自:http://www.51testing.com/html/86/n-1430786.html 除了在ride中执行用例,我们也可以通过命令行的形式执行用例. 1.执行一整个项目 pybot+项 ...

  4. 第三篇:基于K-近邻分类算法的手写识别系统

    前言 本文将继续讲解K-近邻算法的项目实例 - 手写识别系统. 该系统在获取用户的手写输入后,判断用户写的是什么. 为了突出核心,简化细节,本示例系统中的输入为32x32矩阵,分类结果也均为数字.但对 ...

  5. m2014-architecture-imgserver->Lighttpd +mod_mem_cache的效果简直太好了

    公司的图片服务器一直以来负载都比较高,原因是图片比较分散而且比较小.经常把iowait搞的特别的高.但是只有一台机器也法用squid,经测试squid和apache在同一台机器效果会很糟糕的.因为sq ...

  6. date类型数据插入

    --字段类型是dateinsert into tab(column) values(to_date('2017_06_30 11:38:22','yyyy-mm-dd hh24:mi:ss'));-- ...

  7. PHP自带方法验证邮箱、URL、IP是否合法

    PHP验证邮箱.URL.IP是否合法 以前用PHP验证邮箱.URL.IP是否合法都是通过自己写正则来实现,但是有时候脑子发昏,可能会写出一个不是完全正确的正则,导致验证出错,今天发现原来PHP本身自带 ...

  8. LeetCode——Generate Parentheses

    Description: Given n pairs of parentheses, write a function to generate all combinations of well-for ...

  9. Android UsageStats:应用根据启动次数、启动时间、应用名称排序

    Android 7.1.1 developers/samples/android/system/AppUsageStatistics/Application/src/main/java/com/exa ...

  10. 百度地图API功能

    984aca5bc78b070e59f34e230f11cf6d http://api.map.baidu.com/api?v=2.0&ak=您的密钥" <html> & ...