CPU眼里的:this 指针

CPU眼里的:this 指针

编码文章call10242025-03-08 11:57:2252A+A-

用CPU的视角解读this指针的实现原理,看看成员函数背后的秘密


01

提出问题

在C++的编程实践中,我们经常遇到this指针。它让类(class)的成员函数,可以在函数内部,直接访问类的成员变量,这让类(class)成功实现了数据和函数方法的有效集成,彻底让类(class)和结构体(struct)区别开来。可以说this指针,是面向对象不可或缺的技术基石。

但同时这个this指针也像个幽灵,你说它存在吧,你不知道它从哪里来,到哪里去;你说它不存在吧,任何一个成员函数,都可以凭空变出一个this指针出来,如下面的代码所示:

class A
{
public:
    A* mFunc()
    {
        return this;
    }
};

虽然很多书籍都对this指针作了解释,阿布也尊重任何版本的解释。但今天,我们只从CPU的视角,再来看看这个问题。或许,你会发现:this指针,比想象中要简单、通透许多。


02

this的产生和传递

打开Compiler Explorer,编写一个世界上最简单的类;再编写一个世界上最简单的成员函数mFunc;然后,我们再写一个世界上最简单的普通函数func;最后,写一个main函数,作一下函数调用,如图所示。

让我们对比一下成员函数和普通函数,看看它们到底有什么区别?

老规矩,你不需要知道汇编指令的意思,我们只比较它们的差异。如你所见,它们的汇编指令完全相同,成员函数跟带参数(thisPointer)的普通函数func在实现细节上是完全一致的。

所以,我们猜:成员函数,应该存在一个“隐藏”的参数,它就是:this指针。现在,你知道this指针是如何凭空产生的吗?this指针是每一个成员函数必备的默认参数,只是C++语法规则,将它隐藏起来了而已。

那是谁给成员函数,输入这个this指针呢?让我们再看看调用部分,如图所示。

显然,调用成员函数与调用普通函数的CPU指令,又是完全一致!所以,从CPU的视角上看:输入this指针,就是输入对象a的内存地址。

当对象调用成员函数时,都会把自己的内存首地址,也就是所谓的this指针,通过CPU寄存器rdi,传递给成员函数。参数传递的具体细节,还可以参看"CPU眼里的:参数传递"。

所以,现在你明白为什么类(class)的成员函数可以访问成员变量了吧,因为成员函数,一旦获得了类对象的内存首地址(this指针),通过适当的偏移,就可以访问相应的成员变量了。如图所示:

其中CPU寄存器rax保存的就是this指针(类对象的内存首地址),以this指针为基准,做0个字节偏移,就是成员变量x的内存首地址;做8个字节偏移,就是成员变量y的内存首地址。

当然,需要注意的是,类(class)的静态成员变量,不是通过this指针,加上一定的偏移来访问的;相反,类(class)的静态成员变量,跟普通的全局变量、静态变量一样,往往有一个独立、固定的内存地址,具体可以参看"CPU眼里的static、global和local"


03

不一样的this指针

但需要注意的是:this指针不是普通的指针变量,它没有明确的内存存储空间,它的值,可能保存在CPU寄存器里面、堆栈里面,甚至代码段中,具体可以查看章节“CPU眼里的:右值”。跟右值一样,我们也不能对this进行赋值操作,例如:

this = nullptr;

但它又能像普通指针变量一样做间接引用,例如:return *this;同样,在没有完全掌握对象生命周期的情况下,贸然传递和销毁this指针,也可能产生内存泄漏、或运行错误,例如:

delete this;

当然这些都是语法规则上面的约定,只要我们能清楚的了解this所代表的信息,明确this所指向的对象是谁,以及this参数产生、传递的过程,我们就可以有效的驾驭它。


04

总结

  1. this指针不是幽灵,它不能凭空产生。它是每一个成员函数,必须具备的“隐藏参数”,其实现方式,跟有参数的普通函数,完全一致。
  2. 调用成员函数时,必须为成员函数传递:this指针,也就是该对象本身的内存地址。不要忘了,指针的本质就是内存地址。
  3. this指针又不是普通的指针变量,在使用的时候,既有右值的特性,也有左值的特性。关注this指针的合法性,就是在关注对象实体的生命周期。

阿布很欣赏 this 这种简洁的语法操作。但如果能大方的承认,成员函数都会多一个隐藏参数this,这样,会不会更清晰呢?


05

热点问题

Q1:this指针的传递,在x86平台上,好像是通过ecx寄存器完成的。

A1:是的,不同平台,不同编译器,不同的调用约定,对参数传递的方式略有不同,但大多都是通过寄存器传递,至于选择什么寄存器,原则上可以随意发挥,但不同编译器,会有自己不同的规则。不过,天下武功,殊途同归,它们要作的事情都是一样的。


Q2:this指针是不是就相当于python的self,只是C++把this参数,省略了?

A1:十分赞同你的思考。很多编程语言,它们都有相似的使用方法和实现逻辑。C/C++更加偏向底层,这也让我们有机会用CPU的视角,细致的观察它的运行细节。


06

更多知识

如果喜欢阿布这种解读方式,希望更加系统学习这些编程知识的话,也可以考虑看看由阿布亲自编写,并由多位微软大佬联袂推荐的新书《CPU眼里的C/C++》

<script type="text/javascript" src="//mp.toutiao.com/mp/agw/mass_profit/pc_product_promotions_js?item_id=7366841919747457551"></script>
点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4