const 引用的分析

const 引用:

在初始化常量引用时,允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可。尤其,允许为一个常量引用绑定非常量的对象、字面值,甚至是一个表达式。我们来看 const 引用的分析:

#include <iostream>
int main(int argc, char* argv[])
{
    const int &i = 12;
    return 0;
}

该代码的汇编代码如下:

int main(int argc, char* argv[])
{
00964C80  push        ebp
00964C81  mov         ebp,esp
00964C83  sub         esp,0D8h
00964C89  push        ebx
00964C8A  push        esi
00964C8B  push        edi
00964C8C  lea         edi,[ebp-0D8h]
00964C92  mov         ecx,36h
00964C97  mov         eax,0CCCCCCCCh
00964C9C  rep stos    dword ptr es:[edi]
    const int &i = 12;
00964C9E  mov         dword ptr [ebp-14h],0Ch
00964CA5  lea         eax,[ebp-14h]
00964CA8  mov         dword ptr [i],eax  

    return 0;
00964CAB  xor         eax,eax
} 

我们可以看到,const 引用绑定一个12的时候,相当于有如下的步骤:

int temp = 12;

const int &i = temp;

我们上面分析过,引用实质上是一个指针,绑定一个对象就是保存对象的地址,那么一个12是没有地址的,所以需要一个临时变量。当然如果那个常量本身有地址,那么久直接将其地址保存到引用的内存空间。

下面考虑一个常量引用绑定到另一种类型时发生了什么:

int main(int argc, char* argv[])
{
    double num = 23.2;
    const int &i = num;

    return 0;
}

汇编结果:

    double num = 23.2;
000E436E  movsd       xmm0,mmword ptr ds:[0ECD80h]
    double num = 23.2;
000E4376  movsd       mmword ptr [num],xmm0
    const int &i = num;
000E437B  cvttsd2si   eax,mmword ptr [num]
000E4380  mov         dword ptr [ebp-24h],eax
000E4383  lea         ecx,[ebp-24h]
000E4386  mov         dword ptr [i],ecx  

    return 0;
000E4389  xor         eax,eax
}

我们可以看到,这里也是生成了一个临时变量,步骤相当于如下:

const int temp = num;

const int &i = temp;

所以,如果 i 不是常量引用,那么就应该允许对 i 所绑定的对象进行修改,但是 temp 是一个临时变量,明显是一个右值,不合法。

当然,如果是这样的代码

int main(int argc, char* argv[])
{
    const int num = 23;
    const int &i = num;

    return 0;
}

那么就不需要一个中间变量。

于是这里就出现了一个很有趣的问题,当一个 const 引用绑定一个非常量对象的时候,其行为可能是不同的,比如如下:

int main(int argc, char* argv[])
{
    double num = 23.9;
    const int &i = num;
    num = 54.9;
    cout << i << endl;

    return 0;
}

这份代码的结果是:23

而下面这份:

int main(int argc, char* argv[])
{
    int num = 23;
    const int &i = num;
    num = 54;
    cout << i << endl;

    return 0;
}

结果是 54. 就是因为上面那份生成了一个中间变量的原因。

所以在使用 const 引用绑定非 const 变量的时候要注意这个问题。

时间: 2024-08-03 14:10:20

const 引用的分析的相关文章

Python模块的交叉引用问题分析

实际项目中遇到python模块相互引用问题,查资料,说是通过import局部导入的方式可以避免错误,资料如附录所述. 但更改后测试还是会出错,很疑惑!? 如果哪位读者有好的解决方法,敬请留言说明,谢谢. 所以,最好的方法是不进行交叉引用,如果需要就单独分一个模块出来. 附录:Python模块的交叉引用问题解读:How can I have modules that mutually import each other? 有下面两个文件相互引用,Python解释器报错. foo.py: from

python的引用计数分析(二)

python所有对象引用计数被减少1的情况: 一.对象的别名被赋予新的对象; a = 23345455 # 增加了一个引用 b = a # 增加了一个引用 print(sys.getrefcount(a)) b = 1.4 # 减少了一个23345455整数的引用 print(sys.getrefcount(a)) 结果:3:2 二.对象的别名被显式销毁; a = 23345455 # 增加了一个引用 b = a # 增加了一个引用 list = [a, b] # 增加了2个引用 del a p

C++ 中有关const引用的一点小知识

在读<C++ Primer>时,发现之前对const的概念不是很清晰,只知道如何去使用,于是翻开const引用部分又阅读了一遍,发现有两点自己要注意的地方 1.const限定的对象不可以初始化非const引用 ex. 1 const int src = 512; 2 const int &ok_dest = src; //ok: 引用和初始化对象都是const 3 int &err_dest = src; //error : 引用为非const 原因很简单, src 是不可以被

非const引用不能指向临时变量

没找到具体原因,MSDN看到下面这句,VC是从2008才有这一限制的,感觉就是从语法上对临时变量增加了限定,因为一般说来修改一个临时变量是毫无意义的,通过增加限定,强调临时变量只读语义.虽然实际上修改临时变量并不会有问题. Visual Studio 2008 In previous releases of Visual C++, non-const references could be bound to temporary objects. Now, temporary objects ca

C++ Primer 学习笔记_17_从C到C++(3)--引用、const引用、引用传递、引用作为函数返回值、引用与指针区别

欢迎大家阅读参考,如有错误或疑问请留言纠正,谢谢 一.引用 1.引用是给一个变量起别名 变量: 名称 空间 引用: 引用不是变量 引用仅仅是变量的别名 引用没有自己独立的空间 引用要与它所引用的变量共享空间 对引用所做的改变实际上是对它所引用的变量的改变 引用在定义的时候必须要进行初始化 引用一经初始化,不能重新指向其他变量 2.定义引用的一般格式: (1)类型  &引用名 = 变量名: (2)例如: int a=1; int &b=a; // b是a的别名,因此a和b是同一个单元 (3)

深入学习 const指针,const引用

指针和引用的区别: 1.指针可以为空,引用不可以为空. 2.指针初始化后可以重新指向新对象,引用初始化以为不可以重新绑定新对象, 3.指针可以在初始化时赋值,可以初始化以后通过赋值运算符(=)赋值:引用只能在初始化时赋值. 4.指针是个实体(占内存4byte),引用只是个别名(不占内存) 5.指针sizeof是4byte,引用sizeof是绑定对象的大小. 6.指针是类型安全,引用是类型安全的. const对于指针和引用的区别: int a = 1: int b = 1: const int *

为什么赋值操作符函数的参数为const引用,返回值为引用

为什么赋值操作符函数的参数为const引用,返回值为引用 1.返回值类型 返回类型一般声明为类型的引用,并在函数结尾时返回实例自身的引用(即*this).这里主要有两个原因:(1)返回引用可以减少一次拷贝构造和析构函数导致不必要的开销,因为返回值类型不是引用,会创建一个匿名对象,这个匿名对象时个右值,获取return的值.(2)可以实现连续赋值 在例子中 b=c=a; 返回值不是引用类型也是可以的,其运算顺序 b=(c=a); c得到一个右值,再将右值赋给b,所以逻辑上没有问题的.但是如果是 (

C++primer: 引用&amp;与 const 引用

1.什么是引用? 引用就是对象的另外一个名字.在实际程序中,引用主要用作函数的形式参数. 引用是一种复合类型,通过在变量名前面添加"&"符号来定义.复合类型是指用其他类型定义的类型.在引用的情况下,每一种引用类型都"关联到"某一其他类型.不能定义引用类型的引用,但是可以定义任何其他类型的引用. 引用必须用与该引用同类型的对象初始化: int ival = 1024; int& refVal = ival;// ok:refVal refer to i

【c++基础】const、const指针、const引用

一.const常量 声明时必须同时初始化(和“引用”一样) 二.const指针 三.const引用 引用本身和引用的对象都是const对象,可以用字面值来赋给const引用(普通引用则不行) 1 const B=1024; 2 const refB=B; //const变量的声明和初始化 3 4 const int &r=42;//字面值给const赋值 5 int &r2=42;//错 [c++基础]const.const指针.const引用