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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12378271/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 16:13:33  来源:igfitidea点击:

What does an object look like in memory?

c++

提问by NeilMonday

Possible Duplicate:
Structure of a C++ Object in Memory Vs a Struct
memory layout c++ objects

可能的重复:
C++ 对象在内存中的结构与 Struct
内存布局 C++ 对象

This is probably a really dumb question, but I will ask anyway. I am curious what an object looks like in memory. Obviously it would have to have all of its member data in it. I assume that functions for an object would not be duplicated in memory (or maybe I am wrong?). It would seem wasteful to have 999 objects in memory all with the same function defined over and over. If there is only 1 function in memory for all 999 objects, then how does each function know who's member data to modify (I specifically want to know at the low level). Is there an object pointer that gets sent to the function behind the scenes? Perhaps it is different for every compiler?

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

Also, how does the static keyword affect this? With static member data, I would think that all 999 objects would use the exact same memory location for their static member data. Where does this get stored? Static functions I guess would also just be one place in memory, and would not have to interact with instantiated objects, which I think I understand.

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

采纳答案by tenfour

Static class members are treated almost exactly like global variables / functions. Because they are not tied to an instance, there is nothing to discuss regarding memory layout.

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

Class member variablesare duplicated for each instance as you can imagine, as each instance can have its own unique values for every member variable.

可以想象,每个实例的类成员变量都是重复的,因为每个实例对于每个成员变量都可以有自己的唯一值。

Class member functionsonly exist once in a code segment in memory. At a low level, they are just like normal global functions but they receive a pointer to this. With Visual Studio on x86, it's via ecxregister using thiscallcalling convention.

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

When talking about virtual functions, polymorphism, then the memory layout gets more complicated, introducing a "vtable" which is basically a bunch of function pointers that define the topography of the class instance.

说到虚函数、多态,那么内存布局就变得更复杂了,引入了一个“ vtable”,它基本上是一堆定义类实例拓扑的函数指针。

回答by paddy

You've asked a few questions here...

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

Layout

布局

All the non-static members are organised in memory much like a struct. There may be padding if the compiler chooses to put any in. If you have an array of objects, it's just like an array of structs

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

Static members

静态成员

Are stored separately, obviously. One copy.

显然是分开存放的。一份。

Function calls

函数调用

There's a little magic going on behind the scenes for classes. When you call a member function it is much like any other function except it has a different calling convention. Effectively, this inserts the object's pointer (this) into the parameter list.

课程的幕后有一些魔法。当您调用成员函数时,它与任何其他函数非常相似,只是它具有不同的调用约定。实际上,这将对象的指针 (this) 插入到参数列表中。

[edit: the code for the function itself is not stored with your object -- this allows you to do fun things like delete thisand continuing execution of a member function provided you no longer access the object you just deleted].

[编辑:函数本身的代码不存储在您的对象中——这允许您做一些有趣的事情,例如delete this继续执行成员函数,前提是您不再访问刚刚删除的对象]。

When you have overloaded or polymorphic functions, things get a little more magical. This articleis an explanation that I googled up in about 5 seconds. I'm sure there are many more. I've never much concerned myself with the internals of object calls, but it's always nice to know.

当您拥有重载或多态函数时,事情会变得更加神奇。 这篇文章是我在大约 5 秒内搜索到的解释。我相信还有更多。我从不关心对象调用的内部结构,但知道它总是很高兴。

You should try the exercise of making a class exhibiting all these different aspects and look at the assembly generated in each case. I have done that before when tuning some time-critical code.

您应该尝试制作一个展示所有这些不同方面的类的练习,并查看在每种情况下生成的程序集。我之前在调整一些时间关键代码时已经这样做了。

回答by Zdeslav Vojkovic

As you suspect, the data members (fields) are laid out sequentially. This also includes the fields of base classes.

正如您所怀疑的那样,数据成员(字段)是按顺序排列的。这也包括基类的字段。

If the class (or one of its base classes) contain any virtual methods, the layout typically starts with vptr, i.e a pointer to a virtual table (or vtable) which is a table of pointers to function implementations related to that class. Please note that this is not defined by standard, but AFAIK all current compilers use this approach. Also, with multiple inheritance it gets more hairy, so let's ignore it for the moment.

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

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

Fields can take more space then the sum of their individual sizes, which depends on packing (e.g. 1 byte packing ensures there are no gaps, but is less efficient than the 4 or 8 byte packing with regard to performance).

字段占用的空间可能大于其各自大小的总和,这取决于打包(例如,1 字节打包可确保没有间隙,但在性能方面不如 4 或 8 字节打包有效)。

Member functions (non static) receive the pointer to the object, usually via ecx register on x86 architecture. This is also not defined by the standard.

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

Static functions are similar to global functions, and they operate on static class fields (shared for all instances of a class) which are located in the data segment.

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

回答by Edward Strange

First thing to note is that in C++ the term "object" includes things like integers.

首先要注意的是,在 C++ 中,术语“对象”包括整数之类的东西。

Next thing is, structures are laid out pretty much how you'd expect. One member following the next in memory with an undefined amount of padding between.

接下来的事情是,结构的布局非常符合您的预期。一个成员在内存中跟随下一个成员,其间有未定义的填充量。

When a class inherits from another then the class will start with its base class, which in turn may start with a base class of its own. Thus Derived* and Base* will be the same value in cases of single inheritance. Following the base's area (its members) will be the derived class's members in turn, with an undefined amount of padding between them.

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

When a class inherits from more than one base then things become a little different. The base areas are laid out in memory sequentially. Base1 followed by Base2, etc...after which the derived class's members are laid out in turn with an undefined amount of padding between them.

当一个类从多个基类继承时,事情就会变得有点不同。基区在内存中按顺序排列。Base1 后跟 Base2 等......之后派生类的成员依次排列,它们之间有未定义的填充量。

If the object is of a POD class then it is guaranteed that the first member in the class will be at the location in memory the object resides. This means that Class* and Class->firstMember* will be the same value. I don't believe this applies to non-POD entities.

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

In the case of polymorphic classes, those with virtual functions, an additional secret member will be created called the vtable. This isn't guaranteed by anything in the standard, but is pretty much the only way to do it and follow the rules that are. Each class has this, so if your class has bases then it will have its table and you'll have yours for additional functions.

对于具有虚函数的多态类,将创建一个额外的秘密成员,称为 vtable。这在标准中没有任何保证,但几乎是做到这一点并遵循规则的唯一方法。每个班级都有这个,所以如果你的班级有基,那么它会有它的表,你会有你的附加功能。

All member functions will have their names mangled and parameters modified to accept thisas the first argument. This happens behind the scenes as the compiler builds stuff. Virtual functions will be pointed at by the vtable. Non-virtuals will simply be resolved statically and used directly.

所有成员函数都将对其名称进行修改,并将参数修改为接受this作为第一个参数。当编译器构建东西时,这发生在幕后。vtable 将指向虚函数。非虚拟对象将简单地静态解析并直接使用。

Static members are not members of the object created by a class. A static member is simply a global variable with different scope.

静态成员不是由类创建的对象的成员。静态成员只是具有不同作用域的全局变量。

回答by djechlin

It will have its member variables laid out, and also a virtual function table if it is polymorphic which will include a list of pointers to the functions that its virtual methods are actually associated with.

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

Static means just one copy.

静态意味着只有一个副本。