简体   繁体   English

C ++编译器如何创建对象?

[英]What does a C++ compiler do to create an object?

In C code like such: 在这样的C代码中:

{
   int i = 5;
   /* ....... */
}

The compiler will replace the code by moving the Stack pointer down (for stacks growing down) by the size of an int, and places the value 5 in that memory place. 编译器将通过向下移动堆栈指针(对于堆栈向下)移动int的大小来替换代码,并将值5放在该内存位置。

Similarly, in C++ code, what does the compiler do if an object is created? 同样,在C ++代码中,如果创建了一个对象,编译器会做什么? For example: 例如:

class b
{
   public :
           int p;
           virtual void fun();
};

main()
{
   b   obj;
}

What will the compiler do for the above code? 编译器会为上面的代码做些什么? Can anyone explain when memory is allocated, and when memory for the virtual table is allocated, and when the default constructor is called? 任何人都可以解释何时分配内存,何时分配虚拟表的内存,以及何时调用默认构造函数?

On Constructions 论建筑

Logically there is no difference between the two: 从逻辑上讲,两者之间没有区别:

In both case the stack is made large enough to hold the obect and the constructor is called on the object. 在这两种情况下,堆栈都足够大以容纳对象,并在对象上调用构造函数。

Just note: 请注意:

  • The constructor for a POD type does nothing. POD类型的构造函数什么都不做。
  • A user defined type with no constructor has a compiler generated default cosntructor. 没有构造函数的用户定义类型具有编译器生成的默认cosntructor。

You can think about it like this: 你可以这样思考:

int   x;  // stack frame increased by sizeof(int) default construct (do nothing)
B     a;  // stack frame increased by sizeof(B)   default construct.

While: 而:

int   y(6);  // stack frame increased by sizeof(int) Copy constructor called
B     b(a);  // stack frame increased by sizeof(B)   Copy constructor called

Ok. 好。 Of course the constructor for POD types is very trivial and the compiler will do a lot of optimizations (and may all but remove any actual code and even the memory address), but logically it is just fine to think of it happining this way. 当然,POD类型的构造函数非常简单,编译器会进行大量的优化(并且可能除了删除任何实际的代码甚至内存地址),但从逻辑上讲,将它想象成这种方式就好了。

Note: All types have a copy constructor (the compiler defines one if you don't) and the POD types you can logically think of it as copy construcion without any problems. 注意:所有类型都有一个复制构造函数(如果不这样,编译器会定义一个)和POD类型,你可以在逻辑上把它看作是复制构造而没有任何问题。

As for virtual tables: 至于虚拟表:

Let me first note this is an implementation detail and not all compilers use them. 首先请注意,这是一个实现细节,并非所有编译器都使用它们。
But the vtable itself is usually generated at compile time. 但是vtable本身通常是在编译时生成的。 Any object that needs a vtable has an invisable pointer added to the structure (this is included as part of the objects size). 任何需要vtable的对象都有一个不可见的指针添加到结构中(这是作为对象大小的一部分包含的)。 Then during contruction the pointer is set to point at the vtable. 然后在构造期间,指针被设置为指向vtable。

Note: It is impossable to define when the vtable is set as this is not defined by the standard and thus each compiler is free to do it at any time. 注意:定义何时设置vtable是不可能的,因为标准没有定义,因此每个编译器可以随时自由地执行。 If you have a multiple level hierarchy then the vtable is probably set by each constructor from base to most derived and thus probably wrong until the final constructor finishes. 如果你有一个多级层次结构,那么vtable可能是由每个构造函数从基数到大多数派生的,因此可能是错误的,直到最终的构造函数完成。

Note: You can not call virtual functions in the constructor/destructor. 注意:您无法在构造函数/析构函数中调用虚函数。 So all you can say is that the vtable will be correctly initialised only after the constructor has fully completed. 所以你可以说只有在构造函数完全完成后才能正确初始化vtable。

It's semantically the same, the stack pointer gets decremented (for stacks growing down) by sizeof b , then the default constructor is called to set up your instance. 它在语义上是相同的,堆栈指针通过sizeof b递减(对于堆栈增长),然后调用默认构造函数来设置您的实例。

In practice, depending on your architecture and on your compiler (and the flags you pass to it), basic types like in your int example may not get allocated actual memory space on the stack unless it's really required. 实际上,根据您的体系结构和编译器(以及传递给它的标志),像int示例中的基本类型可能无法在堆栈上分配实际内存空间,除非确实需要它。 They'll live in registers until an operation requiring a real memory address is needed (like the & operator). 它们将存在于寄存器中,直到需要实际存储器地址的操作(如&运算符)。

To touch on question about when the virtual table get's allocated. 触及关于何时分配虚拟表的问题。 Usually it does done at compile time (though it does depend on the compiler). 通常它在编译时完成(尽管它取决于编译器)。

The virtual table is static for any given class. 对于任何给定的类,虚拟表都是静态的。 Because of this the compiler can emit the table at compile time. 因此,编译器可以在编译时发出表。 During the initialization of the class the pointer to the virtual table is set to the stored table. 在类的初始化期间,指向虚拟表的指针被设置为存储的表。

Because of this different instances of the same class will point to the same virtual table. 因为同一个类的不同实例将指向相同的虚拟表。

On

   b   obj;

as with an int, the stack pointer is increased by the size of b. 与int一样,堆栈指针增加b的大小。 Then the constructor is called. 然后调用构造函数。 The constructor may or may not call new or any other function to allocate memory. 构造函数可以调用或不调用新函数或任何其他函数来分配内存。 Thats up to the b's implementation. 这是b的实施。 The call itself does not initiate any allocation. 呼叫本身不会启动任何分配。

The vftable is a static object. vftable是一个静态对象。 It is not created with the object itself. 它不是用对象本身创建的。 The object rather contains a 'invisible' pointer that points to its matching vftable. 该对象包含一个指向其匹配的vftable的“不可见”指针。 Its size is include in sizeof(b). 它的大小包括sizeof(b)。

Just to add to previous answers, once the object is constructed, the compiler will do whatever magic is necessary under it's conventions to guarantee the destructor is called when the object goes out of scope. 只是为了添加以前的答案,一旦构造了对象,编译器就会根据它的约定做任何必要的魔术,以保证在对象超出范围时调用析构函数。 The language guarantees this, but most compilers have to do something to follow through on the guarantee (like set up a table of pointers to destructors and rules about when to invoke the various destructors for the various objects). 语言保证了这一点,但大多数编译器必须做一些事情来完成保证(比如设置一个指向析构函数的指针表和关于何时调用各种对象的各种析构函数的规则)。

According to Itanium C++ ABI standard (which, for example, GCC follows), virtual table is stored into a separate memory, global to the translation unit. 根据Itanium C ++ ABI标准(例如,GCC遵循),虚拟表存储在单独的存储器中,全局到翻译单元。

For each dynamic class a virtual table is constructed and is stored under specific name in the object file, like _ZTV5Class . 对于每个动态类,构造一个虚拟表,并以特定名称存储在目标文件中,如_ZTV5Class Classes, whose runtime type is exactly Class will contain pointers to this table. 运行时类型完全为Class将包含指向此表的指针 These pointers will be initialized, adjusted and accessed, but no class contains its virtual table within its instance. 这些指针将被初始化,调整和访问,但没有类在其实例中包含其虚拟表。

So the answer is that virtual tables are allocated at compile time, and during construction only pointers to them are set up. 所以答案是虚拟表是在编译时分配的,并且在构造期间只设置指向它们的指针。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM