对象如何在C ++中存储在内存中?

时间:2022-05-31 21:22:08

How are objects stored in memory in C++?

对象如何在C ++中存储在内存中?

For a regular class such as

对于常规课程,如

class Object
    {
public:
    int i1;
    int i2;
    char i3;
    int i4;
private:
    };

Using a pointer of Object as an array can be used to access i1 as follows?

使用Object作为数组的指针可以用来访问i1如下?

((Object*)&myObject)[0] === i1?

Other questions on SO seem to suggest that casting a struct to a pointer will point to the first member for POD-types. How is this different for classes with constructors if at all? Also in what way is it different for non-POD types?

关于SO的其他问题似乎暗示将结构转换为指针将指向POD类型的第一个成员。如果有构造函数的类,这有什么不同?另外,对于非POD类型,它有何不同?

Edit:

In memory therefore would the above class be laid out like the following?

因此,在记忆中,上述课程的布局如下:

[i1 - 4bytes][i2 - 4bytes][i3 - 1byte][padding - 3bytes][i4 - 4bytes]

5 个解决方案

#1


Almost. You cast to an Object*, and neglected to take an address. Let's re-ask as the following:

几乎。你转换为一个Object *,而忽略了一个地址。让我们重新询问如下:

((int*)&myObject)[0] == i1

You have to be really careful with assumptions like this. As you've defined the structure, this should be true in any compiler you're likely to come across. But all sorts of other properties of the object (which you may have omitted from your example) will, as others said, make it non-POD and could (possibly in a compiler-dependent way) make the above statement not true.

你必须非常小心这样的假设。正如您已定义的结构一样,在您可能遇到的任何编译器中都应如此。但是,正如其他人所说,对象的各种其他属性(您可能已从示例中省略)将使其成为非POD并且可能(可能以编译器相关的方式)使上述语句不正确。

Note that I wouldn't be so quick to tell you it would work if you had asked about i3 -- in that case, even for plain POD, alignment or endianness could easily screw you up.

请注意,如果您询问有关i3的话,我就不会那么快地告诉您它会起作用 - 在这种情况下,即使对于普通的POD,对齐或字节序也可能很容易让您失望。

In any case, you should be avoiding this kind of thing, if possible. Even if it works fine now, if you (or anybody else who doesn't understand that you're doing this trick) ever changes the structure order or adds new fields, this trick will fail in all the places you've used it, which may be hard to find.

无论如何,如果可能的话,你应该避免这种事情。即使它现在工作正常,如果你(或任何不理解你正在做这个技巧的人)改变结构顺序或添加新字段,这个技巧将在你使用它的所有地方失败,这可能很难找到。

Answer to your edit: If that's your entire class definition, and you're using one of the mainstream compilers with default options, and running on an x86 processor, then yes, you've probably guessed the right memory layout. But choice of compiler, compiler options, and different CPU architecture could easily invalidate your assumptions.

回答你的编辑:如果这是你的整个类定义,并且你正在使用一个主流编译器和默认选项,并在x86处理器上运行,那么是的,你可能已经猜到了正确的内存布局。但是,编译器,编译器选项和不同CPU架构的选择很容易使您的假设无效。

#2


Classes without virtual members and without inheritance are laid out in memory just like structs. But, when you start getting levels of inheritance things can get tricky and it can be hard to figure out what order things are in memory (particularly multiple inheritance).

没有虚拟成员和没有继承的类在内存中布局,就像结构一样。但是,当你开始获得继承级别时,事情会变得棘手,很难弄清楚内存中的顺序(特别是多重继承)。

When you have virtual members, they have a "vtable" in memory which contains pointers to the actual function which gets created based on the inheritance hierarchy of the class.

当你有虚拟成员时,它们在内存中有一个“vtable”,它包含指向实际函数的指针,该函数是根据类的继承层次结构创建的。

The bottom line is: don't access classes this way at all if you can avoid it (and also don't memset them or memcpy them). If you must do this (why?) then take care that you know exactly how your class objects are going to be in memory and be careful to avoid inheritance.

底线是:如果你可以避免它,就不要以这种方式访问​​类(也不要将它们memset或memcpy)。如果你必须这样做(为什么?),那么请注意你确切知道你的类对象将如何在内存中并小心避免继承。

#3


It's difference in that this trick is only valid for POD types. That's really all there is to it. The standard specifies that this cast is valid for a POD type, but makes no guarantees about what happens with non-POD types.

不同之处在于此技巧仅对POD类型有效。这就是它的全部内容。该标准指定此强制转换对POD类型有效,但不保证非POD类型会发生什么。

#4


It really depends on the compiler, or rather, it is left up to the compiler to determine the memory layout.

它实际上取决于编译器,或者更确切地说,由编译器决定内存布局。

For instance, a mix of public, private, and protected member variables could be laid out such that each access type is contiguous. Or, derived classes could have member variables interleaved with unused space in the super class.

例如,可以布置公共,私有和受保护成员变量的混合,使得每种访问类型是连续的。或者,派生类可以将成员变量与超类中未使用的空间交错。

Things get worse with virtual inheritance, where the virtually inherited base classes can be layed out anywhere in the memory allocated for that particular instance.

虚拟继承会使事情变得更糟,虚拟继承的基类可以在为该特定实例分配的内存中的任何位置布局。

POD is different because it needs to be compatible with C.

POD是不同的,因为它需要与C兼容。

#5


Usually what matters isn't whether the class has a constructor: what matters is whether the class has any virtual methods. For details, google for 'vtable' and 'vptr'.

通常重要的不是类是否有构造函数:重要的是类是否有任何虚方法。有关详细信息,请搜索“vtable”和“vptr”。

#1


Almost. You cast to an Object*, and neglected to take an address. Let's re-ask as the following:

几乎。你转换为一个Object *,而忽略了一个地址。让我们重新询问如下:

((int*)&myObject)[0] == i1

You have to be really careful with assumptions like this. As you've defined the structure, this should be true in any compiler you're likely to come across. But all sorts of other properties of the object (which you may have omitted from your example) will, as others said, make it non-POD and could (possibly in a compiler-dependent way) make the above statement not true.

你必须非常小心这样的假设。正如您已定义的结构一样,在您可能遇到的任何编译器中都应如此。但是,正如其他人所说,对象的各种其他属性(您可能已从示例中省略)将使其成为非POD并且可能(可能以编译器相关的方式)使上述语句不正确。

Note that I wouldn't be so quick to tell you it would work if you had asked about i3 -- in that case, even for plain POD, alignment or endianness could easily screw you up.

请注意,如果您询问有关i3的话,我就不会那么快地告诉您它会起作用 - 在这种情况下,即使对于普通的POD,对齐或字节序也可能很容易让您失望。

In any case, you should be avoiding this kind of thing, if possible. Even if it works fine now, if you (or anybody else who doesn't understand that you're doing this trick) ever changes the structure order or adds new fields, this trick will fail in all the places you've used it, which may be hard to find.

无论如何,如果可能的话,你应该避免这种事情。即使它现在工作正常,如果你(或任何不理解你正在做这个技巧的人)改变结构顺序或添加新字段,这个技巧将在你使用它的所有地方失败,这可能很难找到。

Answer to your edit: If that's your entire class definition, and you're using one of the mainstream compilers with default options, and running on an x86 processor, then yes, you've probably guessed the right memory layout. But choice of compiler, compiler options, and different CPU architecture could easily invalidate your assumptions.

回答你的编辑:如果这是你的整个类定义,并且你正在使用一个主流编译器和默认选项,并在x86处理器上运行,那么是的,你可能已经猜到了正确的内存布局。但是,编译器,编译器选项和不同CPU架构的选择很容易使您的假设无效。

#2


Classes without virtual members and without inheritance are laid out in memory just like structs. But, when you start getting levels of inheritance things can get tricky and it can be hard to figure out what order things are in memory (particularly multiple inheritance).

没有虚拟成员和没有继承的类在内存中布局,就像结构一样。但是,当你开始获得继承级别时,事情会变得棘手,很难弄清楚内存中的顺序(特别是多重继承)。

When you have virtual members, they have a "vtable" in memory which contains pointers to the actual function which gets created based on the inheritance hierarchy of the class.

当你有虚拟成员时,它们在内存中有一个“vtable”,它包含指向实际函数的指针,该函数是根据类的继承层次结构创建的。

The bottom line is: don't access classes this way at all if you can avoid it (and also don't memset them or memcpy them). If you must do this (why?) then take care that you know exactly how your class objects are going to be in memory and be careful to avoid inheritance.

底线是:如果你可以避免它,就不要以这种方式访问​​类(也不要将它们memset或memcpy)。如果你必须这样做(为什么?),那么请注意你确切知道你的类对象将如何在内存中并小心避免继承。

#3


It's difference in that this trick is only valid for POD types. That's really all there is to it. The standard specifies that this cast is valid for a POD type, but makes no guarantees about what happens with non-POD types.

不同之处在于此技巧仅对POD类型有效。这就是它的全部内容。该标准指定此强制转换对POD类型有效,但不保证非POD类型会发生什么。

#4


It really depends on the compiler, or rather, it is left up to the compiler to determine the memory layout.

它实际上取决于编译器,或者更确切地说,由编译器决定内存布局。

For instance, a mix of public, private, and protected member variables could be laid out such that each access type is contiguous. Or, derived classes could have member variables interleaved with unused space in the super class.

例如,可以布置公共,私有和受保护成员变量的混合,使得每种访问类型是连续的。或者,派生类可以将成员变量与超类中未使用的空间交错。

Things get worse with virtual inheritance, where the virtually inherited base classes can be layed out anywhere in the memory allocated for that particular instance.

虚拟继承会使事情变得更糟,虚拟继承的基类可以在为该特定实例分配的内存中的任何位置布局。

POD is different because it needs to be compatible with C.

POD是不同的,因为它需要与C兼容。

#5


Usually what matters isn't whether the class has a constructor: what matters is whether the class has any virtual methods. For details, google for 'vtable' and 'vptr'.

通常重要的不是类是否有构造函数:重要的是类是否有任何虚方法。有关详细信息,请搜索“vtable”和“vptr”。