【问题标题】:How are objects stored in memory in C++?在 C++ 中,对象是如何存储在内存中的?
【发布时间】:2010-09-29 03:21:19
【问题描述】:

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

对于普通类如

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

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

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

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

编辑:

因此,在内存中,上面的类会像下面这样排列吗?

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

【问题讨论】:

  • 您可能对填充是正确的,只要 int 是 4 字节宽,char 是 1 字节宽。

标签: c++ memory memory-management


【解决方案1】:

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

当您拥有虚拟成员时,它们在内存中有一个“vtable”,其中包含指向基于类的继承层次结构创建的实际函数的指针。

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

【讨论】:

  • 除了没有虚拟成员和继承之外,POD 类也必须没有非公共数据成员,并且没有用户定义的构造函数或析构函数。它们还必须没有非 POD 数据成员。 class 和 struct 之间的区别无关紧要:重要的是 POD 还是非 POD。
  • ... 在实践中,有各种非 POD 类,大多数编译器确实将它们布置为 POD。除了特定编译器的文档中做出的保证之外,依赖它是不明智的。
  • 您确定 POD 类不能使用继承吗?如果它们只继承自 POD 类型怎么办?
【解决方案2】:

不同之处在于这个技巧只对 POD 类型有效。这就是它的全部。标准规定这种转换对 POD 类型有效,但不保证非 POD 类型会发生什么。

【讨论】:

    【解决方案3】:

    通常重要的不是类是否有构造函数:重要的是类是否有虚方法。有关详细信息,请在 google 中查找“vtable”和“vptr”。

    【讨论】:

      【解决方案4】:

      几乎。您投射到一个对象*,而忽略了一个地址。让我们重新问如下:

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

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

      请注意,如果您询问 i3,我不会这么快告诉您它会起作用 - 在这种情况下,即使是普通 POD,对齐或字节序也很容易搞砸您。

      无论如何,如果可能的话,你应该避免这种事情。即使它现在可以正常工作,如果您(或其他任何不了解您正在使用此技巧的人)曾经更改结构顺序或添加新字段,此技巧在您使用过的所有地方都会失败,这可能很难找到。

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

      【讨论】:

      • 谢谢。在问题中添加了 &。
      【解决方案5】:

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

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

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

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

      【讨论】:

        猜你喜欢
        • 2012-12-14
        • 1970-01-01
        • 2022-01-16
        • 2012-08-25
        • 1970-01-01
        • 1970-01-01
        • 2012-09-21
        • 1970-01-01
        相关资源
        最近更新 更多