何时在C ++中初始化“this”指针?

时间:2010-03-20 15:52:47

标签: c++

嗨我有一个关于this指针的问题,当一个对象被构造时,它被初始化了吗?这意味着什么时候可以使用它?虚构表是在构造函数中构造的,与this指针相同吗?

例如,我有一个像这样的代码。输出是8.是否意味着在输入构造函数之前,this指针已经初始化了?

class A{
   public:
     A() { cout<<sizeof(*this);}
     int i;
     int *p; 
};

int main() {      
    A a; 
}

如果是,那么在输入构造函数之前还会发生什么?

如果不是,那么this指针何时初始化?

8 个答案:

答案 0 :(得分:14)

this指针不是对象或类的成员 - 它是您调用的方法的隐式参数。因此,它的传递方式与其他任何参数一样 - 除了你没有直接要求它。

在上面的例子中,构造函数是一种特殊的方法,它又是一种特殊的函数。构造对象时,编译器为它分配内存(在本例中为堆栈,因为amain函数中的局部变量。然后它会自动调用构造函数来初始化对象。

作为调用构造函数的一部分,隐式参数this - 指向对象的指针 - 作为参数传入。

在具有以下签名的方法中......

void MyMethod (const int* p) const;

实际上有两个参数,都是指针。有显式参数p和隐式参数this。该行末尾的const指定this是一个const指针,就像前一个指定p是一个const指针一样。仅存在对该特殊语法的需要,因为this是隐式传递的,因此您不能像其他参数那样以正常方式指定const-ness。

“静态”方法没有隐含的“this”参数,也不能直接访问对象成员 - 可能没有与该调用关联的特定对象。它基本上是一个标准函数而不是一个方法,除了访问私有成员(假设它可以找到一个要访问的对象)。

正如Steve Fallows指出的那样,sizeof (this)在编译时是已知的,因为它是一个指针类型,所有指针(* 1)都具有相同的sizeof值。您看到的“8”表示您正在为64位平台进行编译。此时this可用 - 它指向有效的内存,并且所有成员都已完成构造函数调用。但是,它不一定完全初始化 - 毕竟你仍然在构造函数调用中。

修改

* 1 - 严格来说,这可能不是真的 - 但编译器知道它在这里处理的指针类型,即使该值在运行时才知道。

答案 1 :(得分:7)

未存储this指针。当为占用特定内存位置的对象调用构造函数时,该位置将作为参数传递给构造函数和其他成员函数。

如果this存储在对象中,如何检索该指针?是的,你再次需要this指针:)

答案 2 :(得分:2)

sizeof(* this)在编译时是已知的。所以cout语句没有透露这个的初始化。

鉴于构造函数可以立即开始访问对象的成员,显然这是在构造函数开始之前初始化的。

构造函数之前还会发生什么?好吧可以是任何东西。我不认为标准限制了编译器可以做什么。也许你应该指明你认为可能发生的任何事情。

答案 3 :(得分:2)

  

虚拟表是在构造函数中构造的,与此指针相同吗?

虚构表不是在构造函数中构造的 通常,单个全局v表由同一个类的所有实例共享,并且每个单独的类都有自己的全局v表。
v表在编译时是已知的,并且“构造”在程序加载时间。

this指针在分配时被“构造”(我认为“已分配”是一个更好的术语),即在调用global new operator之后,在输入构造函数之前。< / p>

如果对象是堆栈分配而不是堆分配,则不会调用全局new,但是this仍然可用于分配堆栈空间,这是之前的输入构造函数。

在分配对象的内存之后,在调用构造函数之前分配实例vptr

答案 4 :(得分:2)

  

这是否意味着在输入构造函数之前,this指针已经初始化了?

,在构造函数被调用之前,this指针的值已知。此值可通过构造函数,构造函数initialization lists,析构函数,成员方法中的this关键字获得。 this关键字在表面上表现为方法变量(指针类型)但不是一个;它通常位于寄存器(x86平台上的ecx)上,您通常无法编译&this之类的代码。

  

在输入构造函数之前还会发生什么

至少就this指针而言,发生的第一件事(除非使用placement new)是{{>最终指向的内存 <{ 1}},无论是在堆栈上(如在您的示例中)还是在堆上(使用this。)此时new指针已知。然后,默认构造函数或显式指定的构造函数(通过构造函数初始化列表)在基类(如果有)和非类{ - 3}上被称为成员变量(如果有的话)。如果您的类包含虚方法或析构函数,则在此点之前也会设置类this指针。然后,调用类构造函数体(如果有)。 (构造函数是递归调用的,即当调用基类的构造函数时,调用后者的基类构造函数,后跟非POD成员构造函数,并设置基类“vtable指针,然后是类”构造函数体。)

答案 5 :(得分:0)

this指针是类的每个调用的第一个参数,包括构造函数。

调用类方法时,最后将类的地址压入堆栈(假设此处为cdecl调用约定)。将其读回寄存器以用作此指针。

事实上,构造函数被称为普通成员函数。

您不能拥有虚构造函数,因为构造函数负责设置vtable成员。

答案 6 :(得分:0)

正如nobugz已经指出的那样,你的例子并没有多大意义 - sizeof根据你传递给它的对象的类型产生结果。它在运行时评估其操作数。

那就是说,是的,this在进入ctor之前被初始化了。基本上,编译器为对象分配空间(如果对象具有自动存储持续时间,则在堆栈上;如果具有动态存储持续时间,则使用::operator new)。进入ctor后,基类的ctors(如果有的话)已经完成了。调用ctor时,this会给出为该对象分配的内存地址。

答案 7 :(得分:0)

开始指向当前对象,并且在您进入构造函数体之前已初始化所有成员和基类。

因此,您可以在初始化列表中分发指向 this 的指针,但接收器除了存储它之外不应该做任何其他事情,因为当时指向的实例可能没有完全构造

#include <iostream>

class B;

class A
{
    B* b_ptr;
public:
    A(B* b);
};

class B
{
    A a;
    int i;
public:
    B(): a(this), i(10) {}
    void foo() const { std::cout << "My value is " << i << '\n'; }
};

A::A(B* b):
    b_ptr(b) //Ok to store
{
    b_ptr->foo(); //not OK to use, will access initialized member
}

int main()
{
    B b;
}