问题 如何为班级的私人和公共成员分配内存


在一个类中,私有成员是在公共成员的单独内存中分配的,还是按照定义的顺序分配的所有成员?

例如,

class A { 

private:  
    int a1;
    int a2:3;  
public:  
    int z;  
    int a3:2;  
    int a4:5;  
private:
    int a5:2;
}

a1a2,和 a5 为了记忆分配而聚在一起或者只是简单 a1a2a3a4a5 ?

如果发生夜总会,它可能会改变比特字段的类的大小。


2100
2017-08-25 05:11


起源

你为什么要知道这个? Java是高级别的,不关心这一点,而在c / c ++中,它是另一回事。 - Jonatan Cloutier
等等,为什么是Java标签? - Ben
@Ben:抱歉删除了 - user1660982
那很好解释了很多! - Jonatan Cloutier
@JonatanCloutier如果说私人成员被吵在一起,在上面的例子中,班级的大​​小是否会有所不同? - user1660982


答案:


  • 在给定的可访问性块中,成员的顺序被保留,但在可访问性块之间,成员顺序在C ++ 03中未指定。这意味着a1,a2,a5,z,a3,a4在上面的示例中将是有效的顺序。
  • 在C ++ 11中,这一点得到了加强,因此具有相同可访问性的成员必须按声明的顺序放置。 (例如,在您的示例中禁止a5 a1 a2 f a3 a4,因为在示例中a1和a2之后声明了a5)未指定具有不同可访问性的成员之间的顺序。
  • 编译器可以在任何成员之间插入填充(例如,为了保持对齐)
  • 位字段的表示未指定。它们可以按任何顺序放置,并且不遵守任何先前的规则。因为你不能获取位字段的地址,所以没有机制来观察它。

具体标准参考(强调我的):

C ++ 03 9.2 [class.mem] / 12:

(非联合)类的非静态数据成员 在没有干预访问说明符的情况下声明 被分配,以便以后的成员在类对象中具有更高的地址。由访问说明符分隔的非静态数据成员的分配顺序未指定(11.1)。实施对齐要求可能导致两个相邻成员不能立即分配;因此,可能需要空间来管理虚拟功能(10.3)和虚拟基类(10.1)。

N3376 (第一篇文章C ++ 11草案)9.2 [class.mem] / 13:

(非联合)类的非静态数据成员 具有相同的访问控制 (第11条)被分配,以便后来的成员在类对象中具有更高的地址。具有不同访问控制的非静态数据成员的分配顺序未指定。实施对齐要求可能导致两个相邻成员不能立即分配;因此,可能需要空间来管理虚拟功能(10.3)和虚拟基类(10.1)。

N3376 9.6 [class.bit] / 1:

[...]类对象中位域的分配是实现定义的。位字段的对齐是实现定义的。 [...]

/ 3:

[...]运算符地址&不应用于位域,因此没有指向位域的指针。 [...]


8
2017-08-25 05:35





C ++答案:

我可能会错过一些东西,如果我这样做,请发表评论。

在C ++中,基于类的类型来放置对象。在标准中,我相信只有几种类型的类可以保证成员的排序。

POD或Plain Old Data类/结构的布局与它们出现的完全相同。每个成员跟随上面声明的成员添加填充。 POD类/结构是不包含任何访问修饰符的类,没有任何用户定义的构造函数/析构函数。没有静态声明的成员,并且只包含POD成员类型。

例如:

struct POD {
    int x;
    int y;
    int z;
};

大多数其他类型的类没有定义成员在内存中的布局方式。如果类/结构具有多个访问修饰符,则编译器可以自由地将成员置于其认为合适的位置。同样,C ++应该与Java类似,因为对于大多数不涉及硬件的情况,你不应该非常关心它的布局。

在删除java标记之前添加了以下内容,但仍留待将来参考。

Java答案:

Java不保证对象在内存中的布局方式,你不应该在乎。 JVM可以自由地在内存中布置对象。这意味着对象甚至不必连续存储器。

现在,在我所知道的任何JVM中都没有这样做。更好的猜测是它将对象与C ++中的对象类似。其中每个父类成员放置在子成员之前,并且类中的每个成员根据具有所需填充的大小连续布局。

如果要检查特定对象在内存中的布局方式,可以使用反射和 sun.misc.Unsafe 类。


5
2017-08-25 05:13



请注意,完全允许编译器在可访问性块之间重新排序。例如,如果编译器出于某种原因想要将所有私有成员放在第一位,那么就可以这样做。 - Billy ONeal
@BillyONeal我相信我在C ++答案中涵盖了那一部分。如果措辞在任何地方都没有,我会接受想法来更好地说出来。 - Smith_61
POD与可访问性没有任何关系。 POD没有说出类的布局。 POD类具有可以记忆的功能(std::is_trivially_copyable并且一旦分配了存储,它们就被认为是构造的(没有构造函数调用)。 - Billy ONeal
@BillyONeal我相信POD类型不能使用访问修饰符。使用它们使它不再是POD类型。我应该添加一个更好的POD类型定义。 - Smith_61
啊,我忘了。为了成为标准布局(POD的要求之一),所有访问控制必须相同。因此,例如,如果所有非静态数据成员都是私有的,那就没问题了。但混合公共和私人成员却不是。 - Billy ONeal