“this”指针存储在计算机内存中的哪个位置?

时间:2013-05-16 10:54:55

标签: c++ this-pointer

'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存储在内存中的哪个位置?

6 个答案:

答案 0 :(得分:78)

最简单的方法是将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填写评论,哪里是方法重载的编组,是吗?” - 请输入异议。 :)

将问题转换为“存储参数的位置?”,答案当然是“它取决于”。 :)

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

答案 1 :(得分:63)

其他答案在解释典型编译器如何实现this(通过将其作为隐式第一个参数传递给函数)方面做得非常好。

我认为看看C ++ ISO规范明确说明了什么也很有用。根据C ++ 03 ISO规范,§9.3.2/ 1:

  

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

重要的是要注意this 变量 - 它是表达式,与表达式1 + 2 * 3的方式非常相似一种表达。允许将此表达式的值存储在任何地方。编译器可能将它放在堆栈上并将其作为隐式参数传递给函数,或者可能将其放入寄存器中,并且可以想象它可以将其放入堆或数据段。 C ++规范在这里故意为实现提供了一些灵活性。

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

希望这有帮助!

答案 2 :(得分:33)

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被视为此方法的常规参数。

答案 3 :(得分:18)

this是一个右值(你不能拿它的地址),所以它没有 (必然)占据记忆。取决于编译器 和目标架构,它通常在寄存器中:i0 在Sparc上,ECX与Intel上的MSVC等等。优化器是 活跃,它甚至可以四处走动。 (我在不同的地方看过它 向MSVC注册)。

答案 4 :(得分:9)

this的行为大多类似于函数参数,因此将存储在堆栈中,或者 - 如果架构的二进制调用约定允许 - 在寄存器中。

答案 5 :(得分:0)

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
}

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