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

nag*_*esh 63 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;
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,我调用成员函数add(),接收器对象隐式传递为'this'指针.凡被this存储在内存中?

unw*_*ind 78

最简单的方法是将其this视为隐藏的额外参数,并始终自动传递.

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

size_t String::length(void) const
{
  return strlen(m_string);
}
Run Code Online (Sandbox Code Playgroud)

实际上更像是在引擎盖下:

size_t String__length(const String *this)
{
  return strlen(this->m_string);
}
Run Code Online (Sandbox Code Playgroud)

和一个电话:

{
  String example("hello");
  cout << example.length();
}
Run Code Online (Sandbox Code Playgroud)

变成这样的东西:

cout << String__length(&example);
Run Code Online (Sandbox Code Playgroud)

请注意,上面的转换是简化的,希望能让我的观点更加清晰.不需要用"whaaa填写评论,哪里是方法重载的编组,是吗?" - 请输入异议.:)

这将问题转化为"论据存储在哪里?",答案当然是"它取决于".:)

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

  • 并非每个系统都有称为"ecx"的东西. (6认同)
  • 很好的解释,但我认为__thiscall最常使用`ecx`来存储这个指针. (4认同)
  • AFAIK,这实际上*是*方法的隐藏参数,我错了吗? (3认同)
  • @Spook:因为它对用户完全透明,所以这个论点毫无意义.它可能是以这种方式实现的,但它有什么变化? (2认同)
  • @riv OP想知道:) (2认同)

tem*_*def 64

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

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

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

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

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

希望这可以帮助!


Spo*_*ook 34

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

如果你打电话:

myClass.Method(1, 2, 3);
Run Code Online (Sandbox Code Playgroud)

编译器生成以下代码:

Method(&myClass, 1, 2, 3);
Run Code Online (Sandbox Code Playgroud)

第一个参数实际上是指向的指针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;
}
Run Code Online (Sandbox Code Playgroud)

通过使用__stdcall我强制编译器通过堆栈传递所有参数.如果然后启动调试器并检查汇编代码,您将找到类似以下内容的内容:

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

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

  • 我会警告不要说`this`总是*作为一个隐含的第一个参数传递给函数.这就是大多数实现使`this`工作的方式,但并不要求实际发生这种情况.其他实现也是可能的. (4认同)

Jam*_*nze 18

this是一个右值(你不能取其地址),因此它根本不会(必然)占用内存.根据不同的编译器和目标体系结构,它往往会在寄存器中:在SPARC,ECX与MSVC英特尔,I0等当优化是积极的,它甚至可以左右移动.(我在与MSVC的不同寄存器中看到它).


MvG*_*MvG 9

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