C++11引用临时变量的解析
作者:网络转载 发布时间:[ 2015/8/28 11:42:03 ] 推荐标签:测试开发技术 .NET
工作中遇到一个引用临时变量的问题,经过两天的学习,私以为:不仅弄明白了这个问题,还有些自己的独到见解。
这里使用一个简单的例子来把自己的学习过程和理解献给大家,如果有什么问题请不吝指正。
*************************Code*************************
class Dog
{
public:
Dog(){}
virtual ~Dog(){}
};
void NonConstReference (Dog & dog )
{
//tell the dog to do something here
}
void TestNonConstReference ()
{
NonConstReference( Dog());
}
*************************VS 2013, Level4 (/W4)*************************
warning C4239: nonstandard extension used : 'argument' : conversion from 'Dog' to 'Dog &'
*************************GCC, C++11*************************
-------------- Build: Debug in Test (compiler: GNU GCC Compiler)---------------
mingw32-g++.exe -Wall -fexceptions -g -std=c++11 -c G:MyBackupcodeCodeBlockTestmain.cpp -o objDebugmain.o
G:MyBackupcodeCodeBlockTestmain.cpp: In function 'void TestNonConstReference()':
G:MyBackupcodeCodeBlockTestmain.cpp:18:29: error: invalid initialization of non-const reference of type 'Dog&' from an rvalue of type 'Dog'
G:MyBackupcodeCodeBlockTestmain.cpp:11:6: error: in passing argument 1 of 'void NonConstReference(Dog&)'
Process terminated with status 1 (0 minute(s), 0 second(s))
2 error(s), 0 warning(s) (0 minute(s), 0 second(s))
*************************lvalue, xvalue, prvalue的一般定义*************************
首先lvalue, rvalue 都是针对表达式的;任何一个表达式都可以按照如下归类方式归类:
lvalue指代一个函数或者对象。例如:
E是指针,则*E是lvalue
一个函数的返回值是左值引用,其返回值是lvalue。例如int& foo();
xvalue指代一个对象,但是和lvalue不同,这个对象即将消亡。
prvalue指代一个临时对象、一个临时对象的子对象或者一个没有分配给任何对象的值。例如:
一个函数的返回值是平常类型,其返回值是rvalue。例如int foo();
没有分配给任何对象的值。如5.3,true。
*************************lvalue, xvalue, prvalue的区分*************************
说明:这部分来自C++ PROGRAMMING LANGUAGE 4TH EDTION。
There are two properties that matter for an object when it comes to addressing, copying, and moving:
? Has identity: The program has the name of, pointer to, or reference to the object so that it is possible to determine if two objects are the same, whether the value of the object has changed, etc.
? Movable: The object may be moved from (i.e., we are allowed to move its value to another location and leave the object in a valid but unspecified state, rather than copying;).
It turns out that three of the four possible combinations of those two properties are needed to precisely describe the C++ language rules (we have no need for objects that do not have identity and
cannot be moved).
Using ‘‘m for movable’’ and ‘‘i for has identity,’’ we can represent this classification of expressions graphically:
So, a classical lvalue is something that has identity and cannot be moved (because we could examine it after a move), and
a classical rvalue is anything that we are allowed to move from.
*************************ISO IEC 14882 2011 8.5.3 References*************************
ISO文档使用cv来代表const volatile 修饰符。
并且假设我们使用这样的一种方式来赋值:cv1 T1 dest = cv2 T2 src;
举个例子是:
int src = 123;
const int& dest = src;
void function(const int& dest){};
function(src);
ISO文档首先给出了两个概念:reference-related, reference-compatible。
Given types “cv1 T1” and “cv2 T2,” “cv1 T1” is reference-related to “cv2 T2” if
T1 is the same type as T2, or
T1 is a base class of T2.
“cv1 T1” is reference-compatible with “cv2 T2” if
T1 is reference-related to T2 and
cv1 is the same cv-qualification as, or greater cv-qualification than, cv2.
说明:cv1 >= cv2的情况都有哪些呢:const > 没有修饰符, const volatile > const,etc.
分析一次赋值:cv1 T1 dest = cv2 T2 src; 是否合法采用如下4个步骤:
1.如果dest 是一个lvalue reference,同时:
1.1如果src是一个左值(不是一个bit-filed),并且cv1 T1 是 reference-compatible with cv2 T2的;
1.2如果T2是一个类类型(class, struct, union, etc.),即使cv1 T1 不是 reference-compatible with cv2 T2的,只要cv2 T2可以被转换成cv3 T3类型的一个左值(src1),这时如果cv1 T1 是 reference-compatible with cv3 T3的;
那么,dest 帮定到src,或者src1上。
2.如果cv2 T2 src不能满足1.1,1.2,那么cv1 应该是一个包含const的lvalue reference定义,否则它因该是一个rvalue reference。此时如果cv2 T2满足如下条件:
2.1如果src是一个xvalue, 类类型的prvalue, array prvalue 或者返回左值的函数,并且cv1 T1 是 reference-compatible with cv2 T2的;
2.2如果cv2 T2是类类型的,即使cv1 T1 不是 reference-compatible with cv2 T2的,只要cv2 T2可以被转换成cv3 T3类型的一个2.1规定的值,假设是src1;
那么,dest帮定到src,或者src1上。
3.如果cv2 T2 src也不能满足2.1,2.2,那么编译器为src创建一个临时变量。
3.1创建此临时变量的条件是:cv1 T1 是 reference-related with cv2 T2,并且cv1 >= cv2;
4.如果cv2 T2 src不能满足上面所有的条件,那么cv1 T1应该是一个rvalue reference。此时,如果cv2 T2是一个lvalue的话,编译器应该抱错。
*************************Reference 匹配(过滤)过程*************************
**************************************这里有些例子**************************************
-------------------------------能被规则1处理完毕-------------------------------------------------
double d = 2.0;
double& rd = d; //d, is an lvalue, and the cv1 equals cv2, 1.1能够处理
const double& rcd = d; // d, is an lvalue,
// the cv1 >= cv2: const > 没有修饰符,1.1能够处理
struct A { };
struct B : A
{
operator int&();
} b;
A& ra = b; // b, has a class type: struct;
//cv1 is reference related with cv2, ra is the base class of the b,1.2能够处理
const A& rca = b; // b, has a class type, struct;
//cv1 is reference related with cv2, ra is the base class of the b;
// the cv1 >= cv2: const > 没有修饰符,1.2能够处理
int& ir = B(); // B(), has a class type: struct
//it can be converted to an lvalue of the int&: operator int&()
//cv1 == cv2: cv修饰符都是空,1.2能够处理
相关推荐
更新发布
功能测试和接口测试的区别
2023/3/23 14:23:39如何写好测试用例文档
2023/3/22 16:17:39常用的选择回归测试的方式有哪些?
2022/6/14 16:14:27测试流程中需要重点把关几个过程?
2021/10/18 15:37:44性能测试的七种方法
2021/9/17 15:19:29全链路压测优化思路
2021/9/14 15:42:25性能测试流程浅谈
2021/5/28 17:25:47常见的APP性能测试指标
2021/5/8 17:01:11