这是我的另一个问题的后续问题:What is the optimal order of members in a class?
如果我以公共,受保护和私人轮流的方式组织成员,它是否会改变任何事情(可见性除外)?
class Example
{
public:
SomeClass m_sc;
protected:
char m_ac[32];
SomeClass * m_scp;
private:
char * m_name;
public:
int m_i1;
int m_i2;
bool m_b1;
bool m_b2;
private:
bool m_b3;
};
这个类和一个我在运行时公开所有成员的类有什么区别吗?我想遵循从大到小排序类型的规则(如果可读性没有受到严重损害)。
我认为它根本不会影响编译的程序,就像const
仅在编译期间检查一样。这是对的吗?
答案 0 :(得分:34)
答案取决于语言版本,因为这已从C ++ 03更改为C ++ 11。
在C ++ 03中,规则是:
同一个访问控制块内的成员(即
public
,protected
,private
关键字之一到该集合中的下一个关键字)将按顺序分配课堂上的宣言,不一定是连续的。
在C ++ 11中,规则已更改为:
具有相同访问控制级别(public,protected,private)的成员将按照类中的声明顺序进行分配,而不一定是连续的。
所以在C ++ 03中,你可以保证这一点(我使用@
来表示类中成员的偏移量):
@m_ac < @m_scp
@m_i1 < @m_i2 < @m_b1 < @m_b2
在C ++ 11中,您还有一些保证:
@m_ac < @m_scp
@m_sc < @m_i1 < @m_i2 < @m_b1 < @m_b2
@m_name < @m_b3
在这两个版本中,编译器可以根据需要对不同链中的成员进行重新排序,甚至可以交换链。
请注意,还有一种机制可以进入图片:标准布局类。
如果类没有虚拟,则该类是标准布局,如果所有非静态数据成员具有相同的访问控制,则它没有基类或非标准布局类型或引用类型的非静态数据成员,如果它的继承链中最多只有一个具有任何非静态数据成员的类(即,它既不能定义自己的非静态数据成员,也不能从基类继承某些成员)。
如果一个类是标准布局,那么还可以保证其第一个非静态数据成员的地址与类对象本身的地址相同(这意味着填充不能出现在班级布局)。
请注意,标准布局的条件,以及不做出悲观选择的实际编译器,实际上意味着在标准布局类中,成员将按声明的顺序连续排列(根据需要填充对齐的填充)
答案 1 :(得分:4)
我认为订购规则并不总是最好的。你唯一得到的就是避免&#34;填充&#34;。
然而,另一个&#34;规则&#34;要遵循的是拥有最热情的#34;顶部的成员,以便它们可以放入缓存行,通常是64字节。
想象一下,你有一个循环来检查你的类的标志,它的偏移量是1,你的另一个成员是偏移65,另一个是偏移200.你将得到缓存未命中。
int count = 0;
for (int i = 0; i < 10; i++)
{
if (class->flag/*offset:1*/ == true && class->flag2 == true/*offset:65*/)
count += class->n; /*offset: 200*/
}
该循环将比缓存友好版本慢得多:
int count = 0;
for (int i = 0; i < 10; i++)
{
if (class->flag/*offset:1*/ == true && class->flag2 == true/*offset:2*/)
count += class->n; /*offset: 3*/
}
后一个循环只需要每次迭代读取一个缓存行。它不会变快。