'this'指针存储在计算机内存中的什么位置?

Where is the 'this' pointer stored in computer memory?

本文关键字:什么 位置 this 指针 存储 计算机 内存      更新时间:2023-10-16

究竟在哪里是'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"指针。this存储在内存中的哪个位置?

最简单的方法是认为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);

注意,上面的转换是简化的,希望能使我的观点更清楚一些。不需要在注释中填满"哇,方法重载的编组在哪里,嗯?"我有异议。:)

将问题转换为"参数存储在哪里?",答案当然是"视情况而定"。:)

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

其他答案已经很好地解释了典型编译器如何实现this(通过将其作为隐式的第一个参数传递给函数)。

我认为看看c++ ISO规范对此的明确说明也是有用的。根据c++ 03 ISO规范,§9.3.2/1:

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

重要的是要注意this而不是一个变量——它是一个表达式,就像表达式1 + 2 * 3是一个表达式一样。这个表达式的值几乎可以存储在任何地方。编译器可能把它放在堆栈上,作为隐式参数传递给函数,或者可能把它放在寄存器中,也可能把它放在堆中或数据段中。c++规范故意在这里给实现一些灵活性。

我认为"语言律师"的答案是"这完全是实现定义的,而且this在技术上不是指针,而是一个计算为指针的表达式。"

希望这对你有帮助!

this通常作为方法的隐藏参数传递(不同调用约定的唯一区别是如何)。

如果你调用:

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,我强制编译器通过堆栈传递所有参数。如果然后启动调试器并检查汇编代码,您将发现如下内容:

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

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

this是一个右值(你不能取它的地址),所以它没有(必然)占用内存。取决于编译器而目标体系结构,通常是在寄存器:0中在Sparc上运行,在Intel上运行带有MSVC的ECX等等。当优化器是它很活跃,甚至可以到处移动。我在不同的地方见过注册到MSVC)。

this的行为更像是一个函数参数,因此将被存储在堆栈中,或者(如果体系结构的二进制调用约定允许的话)存储在寄存器中。

this没有存储在一个定义良好的位置!它所指向的对象存储在某个地方,并且具有定义良好的地址,但地址本身没有特定的家庭地址。它在整个项目中传播。不仅如此,该指针还可以有多个副本。

在下面的虚构的init函数中,对象注册自己以接收事件和计时器回调(使用虚构的事件源对象)。所以在注册之后,有两个额外的this副本:

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
}

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