对象在内存中的样子是什么?

时间:2012-09-11 21:36:23

标签: c++

  

可能重复:
  Structure of a C++ Object in Memory Vs a Struct
  memory layout c++ objects

这可能是一个非常愚蠢的问题,但无论如何我都会问。我很好奇对象在内存中的样子。显然,它必须包含其中的所有成员数据。我假设对象的函数不会在内存中重复(或者我错了?)。在内存中拥有999个对象并且反复定义相同的功能似乎很浪费。如果内存中只有1个函数用于所有999个对象,那么每个函数如何知道要修改的成员数据(我特别想知道低级别)。是否有一个对象指针被发送到幕后的函数?也许每个编译器都不同?

另外,static关键字如何影响这个?使用静态成员数据,我认为所有999个对象都将使用完全相同的内存位置作为其静态成员数据。这存储在哪里?静态函数我想它也只是内存中的一个位置,并且不必与实例化对象进行交互,我想这是我理解的。

5 个答案:

答案 0 :(得分:19)

静态类成员的处理方式几乎与全局变量/函数一样。因为它们不依赖于实例,所以没有什么可以讨论内存布局。

如您所想,每个实例都会复制类成员变量,因为每个实例都可以为每个成员变量拥有自己的唯一值。

类成员函数仅在内存中的代码段中存在一次。在较低级别,它们就像普通的全局函数一样,但它们会收到指向this的指针。使用x86上的Visual Studio,它通过ecx使用thiscall调用约定进行注册。

在讨论虚函数,多态时,内存布局变得更复杂,引入了一个“vtable”,它基本上是一组定义类实例地形的函数指针。

答案 1 :(得分:6)

你在这里问过几个问题......

<强>布局

所有非静态成员都在内存中组织,就像结构一样。如果编译器选择放入任何内容,可能会有填充。如果你有一个对象数组,它就像一个结构数组

静态成员

显然是单独存放的。一份。

函数调用

课程幕后有一点魔力。当你调用一个成员函数时,它就像任何其他函数一样,除了它有不同的调用约定。实际上,这会将对象的指针(this)插入参数列表中。

[ edit :函数本身的代码不会与您的对象一起存储 - 这允许您执行有趣的事情,如delete this并继续执行成员函数,前提是您没有更长时间访问刚删除的对象]。

当你有重载或多态函数时,事情会变得更加神奇。 This article是一个解释,我在大约5秒钟内搜索了一下。我相信还有更多。我从不关心对象调用的内部,但知道它总是很好。

你应该尝试制作一个展示所有这些不同方面的课程,并观察每个案例中产生的装配。在调整一些时间关键代码之前,我已经做过了。

答案 2 :(得分:5)

如您所料,数据成员(字段)按顺序排列。这还包括基类的字段。

如果类(或其基类之一)包含任何虚方法,则布局通常以vptr开头,即指向虚拟表(或vtable)的指针,该表是指向与该类相关的函数实现的指针表。请注意,这不是标准定义,但AFAIK所有当前编译器都使用此方法。此外,有了多重继承,它会变得更加毛茸茸,所以我们暂时忽略它。

+-----------+
|  vptr     |  pointer to vtable which is located elsewhere
+-----------+
|  fieldA   |  first member
|  fieldB   |  ...
|  fieldC   |
|  ...      |
+-----------+

字段可以占用更多空间,然后是各自大小的总和,这取决于打包(例如,1字节打包确保没有间隙,但效率低于4或8字节打包的性能)。

成员函数(非静态)接收指向对象的指针,通常通过x86架构上的ecx寄存器。这也没有标准定义。

静态函数类似于全局函数,它们对位于数据段中的静态类字段(对所有类的实例共享)进行操作。

答案 3 :(得分:3)

首先要注意的是,在C ++中,术语“对象”包括整数等内容。

接下来的事情是,结构的布局几乎与你期望的一样。一个成员在内存中跟随下一个未定义的填充量。

当一个类继承自另一个类时,该类将以其基类开始,而基类又可以从它自己的基类开始。因此,在单继承的情况下,Derived *和Base *将是相同的值。在base的区域(其成员)之后依次是派生类的成员,它们之间有不确定的填充量。

当一个类继承自多个基础时,事情会变得有点不同。基区按顺序布置在存储器中。 Base1后跟Base2等...之后,派生类的成员依次布局,并且它们之间有不确定的填充量。

如果对象属于POD类,则保证类中的第一个成员位于对象所在的内存中。这意味着Class *和Class-&gt; firstMember *将是相同的值。我不认为这适用于非POD实体。

对于具有虚函数的多态类,将创建一个名为vtable的附加秘密成员。标准中的任何内容都不能保证这一点,但这几乎是实现它并遵循规则的唯一方法。每个班级都有这个,所以如果你的班级有基础,那么它将拥有它的表格,你将有你的其他功能。

所有成员函数的名称都会被修改,参数会被修改为接受this作为第一个参数。这种情况发生在幕后,因为编译器构建了东西。虚拟功能将由vtable指向。非虚拟化将简单地静态解析并直接使用。

静态成员不是类创建的对象的成员。静态成员只是一个具有不同范围的全局变量。

答案 4 :(得分:0)

它将包含其成员变量,如果它是多态的,还将包含一个虚函数表,其中包含指向其虚拟方法实际关联的函数的指针列表。

静态只意味着一份。