计算机存储器中存储的“this”指针在哪里?

“this”指针在哪里存储在内存中? 它是分配在堆栈中,堆中还是数据段中?

#include <iostream> using namespace std; class ClassA { int a, b; public: void add() { a = 10; b = 20; cout << a << b << endl; } }; int main() { ClassA obj; obj.add(); return 0; } 

在上面的代码中,我调用成员函数add() ,接收者对象作为“this”指针隐式传递。 这里存储在内存中?

其他答案已经做了一个很好的工作,解释了一个典型的编译器如何实现(通过将其作为一个隐含的第一个parameter passing给函数)。

我认为看看C ++ ISO规范明确地说明了这一点也是有用的。 根据C ++ 03 ISO规范,§9.3.2/ 1:

在非静态(9.3)成员函数的主体中,关键字this是一个非左值expression式,其值是调用该函数的对象的地址。

重要的是要注意, this 不是一个variables – 这是一个expression式 ,就像expression式1 + 2 * 3 。 这个expression式的值允许存储在任何地方。 编译器可能把它放在堆栈上,并把它作为一个隐式parameter passing给一个函数,或者把它放到一个寄存器中,并且可以把它放在堆或数据段中。 C ++规范在这里故意给予实现一些灵活性。

我认为“语言律师”的答案是“这是完全实现定义的,而且this在技​​术上不是一个指针,而是一个评估指针的expression式”。

希望这可以帮助!

最简单的方法就是将this视为一个总是自动传递的隐藏的额外参数。

所以,一个虚构的方法,如:

 size_t String::length(void) const { return strlen(m_string); } 

实际上更像是这样下的:

 size_t String__length(const String *this) { return strlen(this->m_string); } 

和一个像这样的电话:

 { String example("hello"); cout << example.length(); } 

变成这样的东西:

 cout << String__length(&example); 

请注意,上面的转换已经简化了,希望能够让我的观点更清晰。 没有必要用“whaaa,方法重载编组在哪里?”填写注释,请input异议。 🙂

这个问题转化为“存储参数在哪里?”,答案当然是“取决于”。 🙂

它通常在堆栈中,但也可能在寄存器中,或者编译器认为对目标架构有利的任何其他机制。

this通常是作为方法的隐藏parameter passing的(在不同的调用约定中,唯一的区别是如何 )。

如果你打电话给:

 myClass.Method(1, 2, 3); 

编译器生成以下代码:

 Method(&myClass, 1, 2, 3); 

第一个参数实际上是指向this的指针。

我们来看看下面的代码:

 class MyClass { private: int a; public: void __stdcall Method(int i) { a = i; } }; int main(int argc, char *argv[]) { MyClass myClass; myClass.Method(5); return 0; } 

通过使用__stdcall我强制编译器通过堆栈传递所有参数。 如果您然后启动debugging器并检查汇编代码,则会发现如下内容:

  myClass.Method(5); 00AA31BE push 5 00AA31C0 lea eax,[myClass] 00AA31C3 push eax 00AA31C4 call MyClass::Method (0AA1447h) 

正如你所看到的,方法的参数通过堆栈传递,然后myClass的地址被加载到eax寄存器并再次被压入堆栈。 换句话说, this被视为这种方法的常规参数。

this是一个右值(你不能接受它的地址),所以它不(必然)占用内存。 根据编译器和目标体系结构的不同,它通常会在一个寄存器中:Sparc中的i0,Intel上的MSVC上的ECX等。当优化器处于活动状态时,甚至可以四处移动。 (我已经看到它与MSVC不同的寄存器)。

this行为大部分就像一个函数参数,因此会被存储在堆栈中,或者如果体系结构的二进制调用约定允许在寄存器中。

this不是存储在一个明确的位置! 它指向的对象存储在某个地方,并有一个定义明确的地址,但地址本身并没有一个特定的家庭地址。 它在程序中传达。 不仅如此,该指针还可以有很多副本。

在下面的想象的init函数中,对象注册自己接收事件和定时器callback(使用假想的事件源对象)。 所以在注册之后,还有两个这样的副本:

 void foo_listener::init() { g_usb_events.register(this); // register to receive USB events g_timer.register(this, 5); // register for a 5 second timer } 

我的一个函数激活链,也会有这个指针的多个副本。 假设我们有一个对象obj并调用它的foo函数。 该函数调用同一个对象的bar函数, bar调用另一个叫update函数。 每个function激活级别都有this指针。 它存储在机器寄存器中,或存储在函数激活的堆栈帧的存储单元中。