c++右值引用
右值
右值是相对与左值来说的。
左值是以变量的形式存在,指向一个指定的内存,可以对它取地址。右值就是不指向任何地方,它是暂时和短命的,不能对它取地址。
右值引用
把临时的、生命周期短的值,绑定到一个变量上,提高它的生命周期,比如
string a = "hello ";
string b = "world"; string c = a + b; // 1.临时变量赋值给c后自动释放 string&& d = a + b; // 2.d 直接指向了临时变量,避免了一次赋值运算
这里的 a+b 会产生一个临时变量,第一种情况,这个临时变量被拷贝构造给了c,之后,这个临时变量析构掉; 第二种情况,这个临时变量被右值引用d接管,它就不会被析构,而是一直存在,直到d退出作用域。
因为右值引用能保存临时变量,所以在有些时候,它可以提高程序的效率,减少不必要的拷贝。
当函数既有左值引用重载,又有右值引用重载的时候,左值引用绑定左值,右值引用绑定右值,如下:
#include <iostream>
#include <utility> void f(int& x) {
std::cout << "lvalue reference overload f(" << x << ")\n";
} void f(const int& x) {
std::cout << "lvalue reference to const overload f(" << x << ")\n";
} void f(int&& x) {
std::cout << "rvalue reference overload f(" << x << ")\n";
} int main() {
int i = ;
const int ci = ;
f(i); // calls f(int&)
f(ci); // calls f(const int&)
f(); // calls f(int&&)
// would call f(const int&) if f(int&&) overload wasn't provided
f(std::move(i)); // calls f(int&&) // rvalue reference variables are lvalues when used in expressions
int&& x = ;
f(x); // calls f(int& x)
f(std::move(x)); // calls f(int&& x)
}
这是move的基础,移动构造,移动赋值的基础。也可以将一个不再需要的实体移除作用域:
std::vector<int> v{,,,,};
std::vector<int> v2(std::move(v)); // binds an rvalue reference to v
assert(v.empty());
左值引用
引用需要被初始化到一个实体或函数。引用本身不是一个实体,它只是一个别名,所以,没有引用数组、指向引用的指针、指向引用的引用
int& a[]; // error
int&* p; // error
int& &r; // error
引用折叠
当使用typedef或者template时候,可能会导致引用折叠:只有两个都是右值引用的时候,才得到右值引用
typedef int& lref;
typedef int&& rref;
int n;
lref& r1 = n; // type of r1 is int&
lref&& r2 = n; // type of r2 is int&
rref& r3 = n; // type of r3 is int&
rref&& r4 = ; // type of r4 is int&&
forward完美转发
先看一段代码:
#include <utility>
#include <iostream> void bar(const int& x)
{
std::cout << "lvalue" << std::endl;
} void bar(int&& x)
{
std::cout << "rvalue" << std::endl;
} template <typename T>
void foo(T&& x)
{
bar(x);
bar(std::forward<T>(x));
} int main()
{
int x = ;
foo(x);
foo();
return ;
}
输出:
lvalue
lvalue
lvalue
rvalue
foo(10)调用时,进入foo函数,执行bar(x)时,x从右值变成了左值。之所以这样,因为x现在成了一个有名字的变量,所以10是bar(x)的左值参数。如果我们想继续保持10的右值语义,就需要forward,bar(forward<T>(x))。forward的作用就是保持move语义
#include <utility>
#include <iostream> void overloaded(const int& x)
{
std::cout << "[lvalue]" << std::endl;
} void overloaded(int&& x)
{
std::cout << "[rvalue]" << std::endl;
} template <class T>
void fn(T&& x)
{
overloaded(x);
overloaded(std::forward<T>(x));
} int main()
{
int i = ;
overloaded(std::forward<int>(i));
overloaded(std::forward<int&>(i));
overloaded(std::forward<int&&>(i)); fn(i);
fn(std::move(i)); return ;
}
这段代码输出结果是:
[rvalue]
[lvalue]
[rvalue]
[lvalue]
[lvalue]
[lvalue]
[rvalue]
只所以这样,是因为 forward 和引用折叠
c++右值引用的更多相关文章
- C++右值引用浅析
一直想试着把自己理解和学习到的右值引用相关的技术细节整理并分享出来,希望能够对感兴趣的朋友提供帮助. 右值引用是C++11标准中新增的一个特性.右值引用允许程序员可以忽略逻辑上不需要的拷贝:而且还可以 ...
- C++ 11 中的右值引用
C++ 11 中的右值引用 右值引用的功能 首先,我并不介绍什么是右值引用,而是以一个例子里来介绍一下右值引用的功能: #include <iostream> #include &l ...
- 图说函数模板右值引用参数(T&&)类型推导规则(C++11)
见下图: 规律总结: 只要我们传递一个基本类型是A④的左值,那么,传递后,T的类型就是A&,形参在函数体中的类型就是A&. 只要我们传递一个基本类型是A的右值,那么,传递后,T的类型就 ...
- c++11的右值引用、移动语义
对于c++11来说移动语义是一个重要的概念,一直以来我对这个概念都似懂非懂.最近翻翻资料感觉突然开窍,因此记下.其实搞懂之后就会发现这个概念很简单,并无什么高深的地方. 先说说右值引用.右值一般指的是 ...
- VS2012 error C2664: “std::make_pair”:无法将左值绑定到右值引用
在vs2012(c++)make_pair()改动: C++: template <class T1, class T2> pair<V1, V2> make_pair(T1& ...
- 右值引用、move与move constructor
http://blog.chinaunix.net/uid-20726254-id-3486721.htm 这个绝对是新增的top特性,篇幅非常多.看着就有点费劲,总结更费劲. 原来的标准当中,参数与 ...
- 【转】C++11 标准新特性: 右值引用与转移语义
VS2013出来了,对于C++来说,最大的改变莫过于对于C++11新特性的支持,在网上搜了一下C++11的介绍,发现这篇文章非常不错,分享给大家同时自己作为存档. 原文地址:http://www.ib ...
- move语义和右值引用
C++11支持move语义,用以避免非必要拷贝和临时对象. 具体内容见收藏中的“C++右值引用” .
- [转载] C++11中的右值引用
C++11中的右值引用 May 18, 2015 移动构造函数 C++98中的左值和右值 C++11右值引用和移动语义 强制移动语义std::move() 右值引用和右值的关系 完美转发 引用折叠推导 ...
- C++ 11 右值引用
C++11中引入的一个非常重要的概念就是右值引用.理解右值引用是学习“移动语义”(move semantics)的基础.而要理解右值引用,就必须先区分左值与右值. 注意:左值右值翻译可能有些问题 *L ...
随机推荐
- datatables之翻页、搜索、排序事件
$(document).ready(function() { $('#table').on('order.dt', function() { console.log('排序'); }).on('sea ...
- 切片操作:MATLAB VS Python
切片操作:MATLAB VS Python 一.MATLAB 矩阵的拆分 1.冒号表达式: t = e1:e2:e3 e1表示初始值,e2为步长,e3为终止值(包括e3),产生一个从e1到e3,步长为 ...
- Java项目性能瓶颈定位
文章目标 当Java项目出现性能瓶颈的时候,通常先是对资源消耗做分析,包括CPU,文件IO,网络IO,内存:之后再结合相应工具查找消耗主体的程序代码.本文主要介绍系统资源消耗的分析过程,以及常用的Ja ...
- 【^.^】hello world~~
一直以来都没有在公共博客上写作的习惯,加之Evernote的强大和方便好用,让我仅仅依赖它就足以满足日常学习笔记的记录和整理. 不过看着Evernote里面记录的大大小小的笔记已经有400+了,觉得应 ...
- Windows 系统System帐号及权限
今天碰到一同事,在那里删除注册表,死活都删除不掉,想起以前在学校的时候老是被莫名的被别人叫过去修电脑(开玩笑,真觉得那时候的我比现在牛B很多),什么删除不掉的东西没见过,然后小小的百度了一下很快就帮他 ...
- Xapian简明教程(未完成)
第一章 简介 1.1 简介 Xapian是一个开源的搜索引擎库,它可以让开发者自定义的开发一些高级的的索引和查找因素应用在他们的应用中. 通过阅读这篇文档,希望可以帮助你创建第一个你的索引数据库和了解 ...
- ABI与编译器:ABI是由内核和工具链定义和实现的
http://book.51cto.com/art/201412/460857.htm <Linux系统编程(第2版)>第1章入门和基本概念,这一章着眼于Linux系统编程的基础概念并从程 ...
- Codeforces 758A Holiday Of Equality
题目链接:http://codeforces.com/problemset/problem/758/A A. Holiday Of Equality time limit per test 1 sec ...
- Windows Thin PC(7月2日发布)下载+激活+汉化
在7月2日Windows 7 瘦身版Windows Thin PC(WinTPC)完成了RTM版的编译开发,WinTPC是一个面向企业用户的产品,主要面向虚 拟桌面基础架构(VDI)消费者,Win ...
- Vuex基础-Mutation
借助官网的一张图,更改 Vuex 的 store 中的状态的唯一方法是提交 mutation.不可以直接对其进行赋值改变.需要注意的是,mutations只能做一些同步的操作. 代码结构: ...