c/c++ 右值引用
c/c++ 右值引用
转自:https://www.cnblogs.com/catch/p/3500678.html
左值(lvalue)和右值(rvalue)是 c/c++ 中一个比较晦涩基础的概念,不少写了很久c/c++的人甚至没有听过这个名字,但这个概念到了 c++11 后却变得十分重要,它们是理解 move/forward 等新语义的基础。
左值右值的定义
左值与右值这两概念是从 c 中传承而来的,在 c 中,左值指的是既能够出现在等号左边也能出现在等号右边的变量(或表达式),右值指的则是只能出现在等号右边的变量(或表达式).
int a;
int b;
a = 3;
b = 4;
a = b;
b = a;
// 以下写法不合法。
= a;
a+b = 4;
在 c 语言中,通常来说有名字的变量就是左值(如上面例子中的 a, b),而由运算操作(加减乘除,函数调用返回值等)所产生的中间结果(没有名字)就是右值,如上的 3 + 4, a + b 等。我们暂且可以认为:左值就是在程序中能够寻值的东西,右值就是没法取到它的地址的东西(不完全准确),但如上概念到了 c++ 中,就变得稍有不同。具体来说,在 c++ 中,每一个表达式都会产生一个左值,或者右值,相应的,该表达式也就被称作“左值表达式", "右值表达式"。对于基本数据类型来说(primitive types),左值右值的概念和 c 没有太多不同,不同的地方在于自定义的类型,而且这种不同比较容易让人混淆:
对于基础类型,右值是不可被修改的(non-modifiable),也不可被 const, volatile 所修饰(cv-qualitification ignored)
对于自定义的类型(user-defined types),右值却允许通过它的成员函数进行修改。
对于 1),这和 c 是一致的,2) 却是 C++ 中所独有, 因此,如果你看到 C++ 中如下的写法,千万不要惊讶:
#include <iostream>
using namespace std;
class Test{
public:
Test(int d) : data(d){cout << "create:" << data << endl;}
~Test(){cout << "free:" << data << endl;}
Test& operator = (const Test& other){
//data = other.data;
cout << "operator" << endl;
return *this;
}
int get_data() const {return data;}
void set_data(int d){data = d;}
private:
int data;
};
Test getTest(){
int static i = 0;
return Test(i++);
}
void func(Test& t){
cout << "func:" << t.get_data() << endl;
}
int main(){
//1 合法
(getTest() = Test(1)).set_data(12);
getTest() = Test(2);
getTest().set_data(20);
//2 只能用const引用接收右值引用
const Test& ref = getTest();
//Test& ref1 = getTest();//error
//3
//func(getTest());
func(getTest() = getTest());
}
这个特性看起来多少有些奇怪,因为通常来说,自定义类型应该设计得和内置类型尽量一样(所谓 value type,value semantic),但允许成员函数改变右值这个特性却有意无意使得自定义类型特殊化了。对此,我们其实### 可以这样想,也许会好理解点:
<font color="red"自定义类型允许有成员函数,而通过右值调用成员函数是被允许的,但成员函数有可能不是 const 类型,因此通过调用右值的成员函数,也就可能会修改了该右值,done!
左值引用,右值引用
关于右值,在 c++11 以前有一个十分值得关注的语言的特性:右值能被 const 类型的引用所指向,所以如下代码是合法的。
const Test& ref = getTest();
而且准确地说,右值只能被 const 类型的 reference 所指向,非 const 的引用则是非法的:
Test& ref1 = getTest();//error
当一个右值被 const 引用指向时,它的生命周期就被延长了。其中暗藏的逻辑其实就是:右值不能当成左值使用(但左值可以当成右值使用)。另外值得注意的是,对于前面提到的右值的两个特性:
允许调用成员函数。
只能被 const reference 指向。
它们导致了一些比较有意思的结果,比如:
void func(Test& c)
{
cout << "c:" << c.get_data() << endl;
}
//error
func(getTest());
//正确
func(getTest() = getTest());
其中: func(get_cs() = get_cs()); 能够被正常编译执行的原因就在于,cs 的成员函数 operator=() 返回的是 cs&!
不允许非 const reference 引用 rvalue 并不是完美的。
c/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 ...
随机推荐
- RabbitMQ系列(三)RabbitMQ交换器Exchange介绍与实践
RabbitMQ交换器Exchange介绍与实践 RabbitMQ系列文章 RabbitMQ在Ubuntu上的环境搭建 深入了解RabbitMQ工作原理及简单使用 RabbitMQ交换器Exchang ...
- 为Spring Cloud Config插上管理的翅膀
最近一致在更新Spring Cloud Config的相关内容,主要也是为这篇埋个伏笔,相信不少调研过Spring Cloud Config的用户都会吐槽它的管理能力太弱.因此,就有了下面为讲推荐的这 ...
- C#之WebApi权限认证_学习笔记1
自己并不懂,在此先记录下来,留待以后学习... 正文 前言:最近,讨论到数据库安全的问题,于是就引出了WebApi服务没有加任何验证的问题.也就是说,任何人只要知道了接口的url,都能够模拟http请 ...
- C#文件操作。
文件操作常用相关类: File: 操作文件,静态类,对文件整体操作. Directory:操作目录(文件夹),静态类. FileInfo:文件类,用来描述一个文件对象,获取指定目录下的所有文件时,返回 ...
- 28.QT-QPainter介绍
介绍 可以在QPaintDevice类上绘制各种图形 QPaintDevice类表示QPainter的绘图设备(画布) QpaintDevice子类有QImage.QOpenGLPaintDevice ...
- spring_08aop原理及案例
*参考优质文档: https://www.cnblogs.com/xrq730/p/4919025.html 一.简介 aop(Aspect Oriented Programming)是面向切面编程, ...
- 【Spring】16、注解事务 @Transactional
概述 事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性.Spring Framework对事务管理提供了一致的抽象,其特点如下: 为不同的事务API提供一致的编程模型, ...
- 三问助你Fundebug
译者按: Debug也要三省吾身! 原文: Three Questions About Each Bug You Find 译者: Fundebug 为了保证可读性,本文采用意译而非直译.另外,本文版 ...
- JS 操作svg画图
背景: 一共有3个文件:svg文件,html文件,js文件. 有一个svg图,使用embed标签,引入到了html文件中 svg文件: <svg width="640" he ...
- thinkphp模板中,checkbox回显问题
thinkphp 模板里面可以这样写包含操作 //in 标签 <in name="变量名" value="值1,值2,...">要输出的内容< ...