C++引用的实现

当我学习C++引用时,听到的第一句话是“引用是变量的别名,不像指针一样需要占用内存空间”。然而学到深处,发现此话并不完全正确。

本文主要介绍我如何通过实验来了解到C++引用的实现,其实引用的内部就是指针。当然这也于编译器有关,所以这里需要提及一下测试所用的编译器及环境。

测试环境是MinGW的g++ 8.1.0,64位编译器,64位的机子。所以指针的大小是8个字节,即64个bit。(注:因为目的是测试,所以测试时并没有处理对new操作符所产生对象的回收)

首先我写出了如下代码,试图通过指针偏移来获取有关引用的信息:

#include <iostream>
#include <string>
using namespace std;

int main() {
    int64_t x;
    string& str = *new string();
    int64_t y;

    cin >> str; // 对引用做一次操作,避免编译器把变量优化掉

    cout << &x << endl;
    cout << &y << endl;
    cout << str << endl;

    return 0;
}

然而,这个程序的输出如下(str的输出忽略):

0x61fe00
0x61fdf8

难道引用真的不占内存?编译器真的很聪明,可能优化掉了吧;经过一系列尝试,我写出了另外一段代码:

#include <iostream>
#include <string>
using namespace std;

void foo(int64_t q, string& s, int64_t r) {
    cout << "&q: " << &q << endl;
    cout << "&r: " << &r << endl;

    cout << "*(string**)(&q + 1): " << *(string**)(&q + 1) << endl;
}

int main()
{
    string& str = *new string();
    cout << "main(): " << &str << endl;
    foo(0, str, 0);
    return 0;
}

这段代码的输出是:

main(): 0x1e1bd0
&q: 0x61fde0
&r: 0x61fdf0
*(string**)(&q + 1): 0x1e1bd0

可见,q的地址是0x61fde0,r的地址是0x61fdf0。两个地址间相差16个字节!这里引用占用的内存出来了。显然引用对应的指针存储在q的8个字节之后。我们可以将q的地址加1,也就是加上8个字节,这里存储的就是引用的信息。假设它就是指针,那么考虑:(&q + 1)本身是一个指向string*的指针,也就是string**。所以若要获取指针的值,需要对这个值解一次引用,输出出来。(当然如果你想简单一点,可以直接把它转成int64_t然后用16进制输出亦可)

至此真相大白,程序输出的最后一行0x1e1bd0与主函数中new出来的对象的地址(见输出第一行)一致。所以得出结论:引用是用指针实现的。用户对引用的访问操作都内含一次解引用,而这对用户来说是透明的

不过需要提及的是,回想本文的第一个测试,发现引用的指针空间被优化掉了。所以引用有时也不一定会在栈上真正以指针体现出来。

原文链接: https://www.cnblogs.com/sandychn/p/12436069.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍

    C++引用的实现

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/194036

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年2月12日 下午6:33
下一篇 2023年2月12日 下午6:34

相关推荐