嗨我有一个关于this
指针的问题,当一个对象被构造时,它被初始化了吗?这意味着什么时候可以使用它?虚构表是在构造函数中构造的,与this
指针相同吗?
例如,我有一个像这样的代码。输出是8.是否意味着在输入构造函数之前,this
指针已经初始化了?
class A{
public:
A() { cout<<sizeof(*this);}
int i;
int *p;
};
int main() {
A a;
}
如果是,那么在输入构造函数之前还会发生什么?
如果不是,那么this
指针何时初始化?
答案 0 :(得分:14)
this
指针不是对象或类的成员 - 它是您调用的方法的隐式参数。因此,它的传递方式与其他任何参数一样 - 除了你没有直接要求它。
在上面的例子中,构造函数是一种特殊的方法,它又是一种特殊的函数。构造对象时,编译器为它分配内存(在本例中为堆栈,因为a
是main
函数中的局部变量。然后它会自动调用构造函数来初始化对象。
作为调用构造函数的一部分,隐式参数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;
}