【Cpp】引用的本质

一、什么是引用

引用是C++中的一个新的语言特性,从表面来说,引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。引用的声明如下:

类型标识符 &引用名 = 目标变量名;

这里面的&不是位运算、不是取地址,而是一个引用的标识符,可以认为是一个“类型标识符 &”类型,类型标识符是指目标变量的类型。如:

int a = 10;
int &b = a;
b = 5;
std::cout << "the value of a is:" << a << std::endl;

其中符号b就是引用a,是int &类型的,表示一切对b的操作都是对a的直接操作,所以打印的结果是5。关于引用需要注意以下几点:

  1. 声明引用时,必须同时对其进行初始化成某个变量
  2. 引用一旦声明,不可以更改,不能再作为其它变量的引用
  3. 只能引用变量,不能引用常量和表达式
  4. C++标准并没有规定引用是否占用内存空间,很多书和博客认为引用本身不占存储单元,系统也不给引用分配存储单元。个人觉得这是以偏概全,是错误的,因为引用怎么实现还是得依赖于编译器的,而是否占空间也要视情况而定。

二、引用的本质

前面我们说到,引用的具体实现得看编译器,如果我们在结构体类型中定义一个引用,然后测试大小:

#include <iostream>

typedef struct mystruct1
{
    char *a;
    char b;
    char &c = b;
}MS1;

int main(void)
{
    mystruct1 test1;
    test1.b = 'a';
    test1.c = 'b';
    std::cout << "test1.b = " << test1.b << std::endl;
    std::cout << "sizeof(MS1) = " << sizeof(MS1) << std::endl;
    return 0;
}

测试结果如下
clipboard_20200216062249.png
我们看到,如果用64位的g++编译,结构体的大小为24,我们知道char *是占8字节的,如果引用不占内存空间的话,那么结构体大小应该为16。在IDE中,IDE也给出了“小警告”:"padding struct 'mystruct1' with 7 bytes to align 'c'":
clipboard_20200216062612.png
这是说结构体会填充7字节去对齐c。更加说明了结构体中引用是占内存的,而且在64位环境下是8字节(如果是4字节/2字节,结构体只需填充3字节去对齐c,最后的大小为16)

那么,g++是怎么实现引用的呢?我们先来看一段测试代码,里面是两个函数:

void func1(int *a)
{
    int &b = *a;
}

void func2(int *a)
{
    int * const b = a;
}

我们对其进行编译,然后把目标文件进行反汇编,结果如下:
clipboard_20200216063136.png
是不是很吃惊??!两个函数编译之后进行反汇编得到的结果是一样的!也就是说,在g++中将引用实现为一种类型int &,本质上就是int * const类型,也就是说这是一个弱化了的指针,所以是占内存空间的!我们知道对于int * const p = &a来说,指针p指向的地址是不可变的,但是该地址的内容是可变的;这和引用一旦声明,不可以更改,不能再作为其它变量的引用是一致的。

三、引用的使用

引用主要用在函数传参和返回值中,在一定范围内用来代替指针

3.1 const与引用

int a = 10;
const int &b = a;

如上述代码段,我们在定义引用的时候在前面加const关键字,称为“常引用”。这时b的类型是const int &,其值是无法修改的,等价于const int * cont,也就是说不能通过常引用去修改其引用的值,这个一般是在函数传参时使用,防止错误操作

int mul(const int &a)
{
    return a * 10;
}

3.2 引用的典型案例————swap函数

如果我们需要一个函数交换a和b的值,在C语言中是这样做的

void swap(int *pa, int *pb)
{
    *pa ^= *pb;
    *pb ^= *pa;
    *pa ^= *pb;
}
swap(&a, &b);

由于指针过于强大,如果程序员无法控制,就会引发一系列不可预知的错误。在C++中,我们可以通过引用来实现对指针的局部替换

void swap(int &ra, int &rb)
{
    ra ^= rb;
    rb ^= ra;
    ra ^= rb;
}
swap(a, b);
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值