[转载]非常量引用的初始值必须为左值的问题
首先,先看下面一个例子:
eg.1
#include<</span>iostream>
usingnamespace std;
int main(){
int i =2;
double &r =i;
return 0;
}
gcc error: invalid initialization of reference of type 'double&' from expression of type 'int'
如果改成 const double &r =i;没有问题。
难道这里的i不是左值?
程序改成 :
eg.2
int main(){
double i =2;
double &r =i;
return 0;
}
没有错误
难道这里的i又是左值啦?
其实:
const double &r = i;
由于类型不匹配,实际相当于:
const double inner_tmp = (double)i; //这里就产生了一个临时变量
const double &r = inner_tmp;
临时的中间变量都是const,所有没有const的引用会失败。
左值与右值的区分
首先理解什么是右值引用(下面是百度百科给出的解释):
右值引用(及其支持的Move语意和完美转发)是C++0x将要加入的最重大语言特性之一,这点从该特性的提案在C++ - State of the Evolution列表上高居榜首也可以看得出来。从实践角度讲,它能够完美解决C++中长久以来为人所诟病的临时对象效率问题。从语言本身讲,它健全了C++中的引用类型在左值右值方面的缺陷。从库设计者的角度讲,它给库设计者又带来了一把利器。从库使用者的角度讲,不动一兵一卒便可以获得“免费的”效率提升… 在标准C++语言中,临时量(术语为右值,因其出现在赋值表达式的右边)可以被传给函数,但只能被接受为const &类型。这样函数便无法区分传给const &的是真实的右值还是常规变量。而且,由于类型为const &,函数也无法改变所传对象的值。C++0x将增加一种名为右值引用的新的引用类型,记作typename &&。这种类型可以被接受为非const值,从而允许改变其值。
区分左值与右值:
C++ 11中引入的一个非常重要的概念就是右值引用。理解右值引用是学习“移动语义”(move semantics)的基础。而要理解右值引用,就必须先区分左值与右值。
对左值和右值的一个最常见的误解是:等号左边的就是左值,等号右边的就是右值。
左值和右值都是针对表达式而言的,左值是指表达式结束后依然存在的持久对象,右值是指表达式结束时就不再存在的临时对象。一个区分左值与右值的便捷方法是:看能不能对表达式取地址,如果能,则为左值,否则为右值。下面给出一些例子来进行说明。
int b = 20;
int* pFlag = &a;
vector<<span style="color: rgb(0, 0, 255); ">int> vctTemp;
vctTemp.push_back(1);
string str1 = "hello ";
string str2 = "world";
const int &m = 1;
请问,a,b, a+b, a++, ++a, pFlag, *pFlag, vctTemp[0], 100, string("hello"), str1, str1+str2, m分别是左值还是右值?
什么是左值引用:
区分清楚了左值与右值,我们再来看看左值引用。左值引用根据其修饰符的不同,可以分为非常量左值引用(eg.1 double &r =i;)和常量左值引用(eg.1 const double &r =i;)。
非常量左值引用只能绑定到非常量左值,不能绑定到常量左值、非常量右值和常量右值。如果允许绑定到常量左值和常量右值,则非常量左值引用可以用于修改常量左值和常量右值,这明显违反了其常量的含义(eg.1中就是出现了非常量左值引用绑定到常量右值的情况)。如果允许绑定到非常量右值,则会导致非常危险的情况出现,因为非常量右值是一个临时对象,非常量左值引用可能会使用一个已经被销毁了的临时对象。
常量左值引用可以绑定到所有类型的值,包括非常量左值、常量左值、非常量右值和常量右值。
为什么要区分非常量右值引用:
可以看出,使用左值引用时,我们无法区分出绑定的是否是非常量右值的情况。那么,为什么要对非常量右值进行区分呢,区分出来了又有什么好处呢?这就牵涉到C++中一个著名的性能问题——拷贝临时对象。考虑下面的代码:
{
vector<<span style="color: rgb(0, 0, 255); ">int> vctTemp;
vctTemp.push_back(90);
vctTemp.push_back(95);
returnvctTemp;
}
当使用vector vctScore = GetAllScores()进行初始化时,实际上调用了三次构造函数。尽管有些编译器可以采用RVO(Return Value Optimization)来进行优化,但优化工作只在某些特定条件下才能进行。可以看到,上面很普通的一个函数调用,由于存在临时对象的拷贝,导致了额外的两次拷贝构造函数和析构函数的开销。当然,我们也可以修改函数的形式为void GetAllScores(vector &vctScore),但这并不一定就是我们需要的形式。另外,考虑下面字符串的连接操作:
strings = s1 + "a"+ "b"+ "c"+ "d"+ "e";
在对s进行初始化时,会产生大量的临时对象,并涉及到大量字符串的拷贝操作,这显然会影响程序的效率和性能。怎么解决这个问题呢?如果我们能确定某个值是一个非常量右值(或者是一个以后不会再使用的左值),则我们在进行临时对象的拷贝时,可以不用拷贝实际的数据,而只是“窃取”指向实际数据的指针(类似于STL中的auto_ptr,会转移所有权)。C++ 11中引入的右值引用正好可用于标识一个非常量右值。C++ 11中用&表示左值引用,用&&表示右值引用,如:
右值引用根据其修饰符的不同,也可以分为非常量右值引用和常量右值引用。
非常量右值引用只能绑定到非常量右值,不能绑定到非常量左值、常量左值和常量右值(VS2010 beta版中可以绑定到非常量左值和常量左值,但正式版中为了安全起见,已不允许)。如果允许绑定到非常量左值,则可能会错误地窃取一个持久对象的数据,而这是非常危险的;如果允许绑定到常量左值和常量右值,则非常量右值引用可以用于修改常量左值和常量右值,这明显违反了其常量的含义。
常量右值引用可以绑定到非常量右值和常量右值,不能绑定到非常量左值和常量左值(理由同上)。可以看出,使用左值引用时,我们无法区分出绑定的是否是非常量
转载于:https://www.cnblogs.com/zhoug2020/p/7821125.html
[转载]非常量引用的初始值必须为左值的问题相关推荐
- 非常量引用的初始值必须为左值解决方式
看下面的这个函数与调用,这个时候就会出现非常量引用的初始值必须为左值解决方式的错误 修改方法:函数声明的时候,加一个constPoint3f getWorldPoints(const Point2f& ...
- C++中“非常量引用的初始值必须是左值”的处理方法
原文:https://blog.csdn.net/hou09tian/article/details/80565343 1 左值和右值 在C++中,左值可以出现在赋值语句的左边和右边:右值只能出现在赋 ...
- 非常量引用的初始值必须是左值_C++核心编程--引用
2 引用 2.1 引用的基本使用 作用: 给变量起别名 语法: 数据类型 &别名 = 原名 示例: int main() {int a = 10;int &b = a;cout < ...
- 非常量引用的初始值必须为左值
问题描述 先看一段报错的代码: #include<iostream> using namespace std;int main() {int i = 2;double &r = i ...
- ×××××sales_data通过类型转换形成的临时对象不能转换成sales_data (非常量引用)
文件 sales_data.h #include <iostream> #include <string> using namespace std; struct sale ...
- 临时变量不能作为非const引用
int func(a) {return a; }int main() {int r = func(3 + 5);return 0; } 上述代码报错, 非常量引用的初始值必须为左值 . 主要原因如下 ...
- c++左值和右值、 左值引用与右值引用
c++ 左值引用与右值引用--原 左值和右值 综述 C++对于左值和右值没有标准定义,但是有一个被广泛认同的说法: 可以取地址的,有名字的,非临时的就是左值:--变量.返回引用.const 不能取地址 ...
- 左值右值,左值引用和右值引用及其用途
目录 1.左值和右值 2.引用 (1)左值引用 (2)右值引用 3.左值引用的用途 (1)作为复杂名称变量的别名 (2)用于rangeFor循环 (3)避免复制大的对象 (4)参与函数中的参数传递 4 ...
- C++ 常量引用用法详解
"常量引用"其实是"对 const 的引用"的简称. 顾名思义,它把它所指向的对象看作是常量(不一定是常量),因此不可以通过该引用来修改它所指向的对象的值. 严 ...
最新文章
- Jenkins安装maven integration plugin失败解决方法
- 如何使错误日志更加方便排查问题
- fftw库 vs2019_FFTW库在VS 2010中的使用方法
- socket的NIO操作
- iOS 5将加入全新的通知信息和桌面Widgets
- [react] react兄弟组件如何通信?
- python假如输入错误重新输入_认识python之输入(4)
- usage: git remote add [options] name url -f, --fetch fetch the remote branches ...
- 使用Asp.net MVC 2.0 +.NET 4.0 出现 “从客户端 ... 中检测到有潜在危险的 Request.Form 值”错误的解决办法...
- 学习笔记——RuntimeException
- [挖坟] 突破WINISO未注册时100M限制
- 算术关系和逻辑关系---皮尔斯逻辑之二
- Google桌面搜索使用与技巧
- postman安装使用教程(标贝科技)
- keil5工程函数无法跳转到函数定义解决方法
- 基于Wemos的wifi避障小车部分代码
- 使用阿里云服务器三分钟搭建网站
- Windows下x64反汇编参数传递约定,一句话,调用顺序为从左到右, Function( rcx, rdx, r8,r9, [rsp+0x20], [rsp+0x28], [rsp+0x30]..
- 调用百度汇率api 获取各国的汇率值
- Linux基本命令 初级10个
热门文章
- python编程中常用的12种基础知识总结
- imp导入时出现imp-00017 ora-06550的解决办法
- Win7 一键获得管理所有权限(最高权限)注册表
- 网络学习(二十七)Windows XP 加入 Windows Server 2003 Active Directory
- SQL Server 2008带字段注释导入Power Designer 9.5
- 如何做一份出色的竞品分析?(一)
- NPV Formula in Excel
- 关于mbzuai的offer的三点思考
- C# StopWatch的BUG????
- 字符串周期--hdu 3746 Cyclic Nacklace