考虑以下结构:
class Foo {
int a;
};
用g ++进行测试,我得到sizeof(Foo) == 4
,但标准是否有保证?是否允许编译器注意到a
是未使用的私有字段并将其从类的内存中表示中删除(导致较小的sizeof)?
我不希望任何编译器真正进行那种优化,但这个问题出现在语言律师讨论中,所以现在我很好奇。
答案 0 :(得分:3)
C ++标准没有定义很多关于内存布局的内容。本案的基本规则是9 Classes
部分下的第4项:
4类类型的完整对象和成员子对象应具有非零大小。 [注意:类对象可以被赋值,作为参数传递给函数,并由函数返回(除了已经限制复制或移动的类的对象之外;参见12.8)。其他合理的运算符,例如相等比较,可以由用户定义;见13.5。 - 结束说明]
现在还有一个限制:标准布局类。 (没有静态元素,没有虚拟,所有成员的可见性相同)第9.2 Class members
节要求标准布局类的不同类之间的布局兼容性。这可以防止从这些类中删除成员。
对于非平凡的非标准布局类,我认为标准没有进一步的限制。 sizeof(),reinterpret_cast(),...的确切行为是实现定义的(即5.2.10“映射函数是实现定义的。”)。
答案 1 :(得分:3)
答案是肯定的,不是。编译器无法在标准中完全展示出这种行为,但它可以部分地表现出来。
如果永远不会引用该存储,那么编译器无法优化结构存储的原因是没有理由的。如果编译器正确地进行了分析,那么您编写的程序就无法判断存储是否存在。
但是,编译器无法报告较小的sizeof()。标准很清楚,对象必须足够大以容纳它们包含的位和字节(参见例如N3797中的3.9 / 4),并且报告小于保持int所需的sizeof将是错误的。
在N3797 5.3.2:
sizeof运算符产生对象中的字节数 其操作数的表示
我不认为“表示”可以根据结构或成员是否被引用而改变。
另一种看待它的方式:
struct A {
int i;
};
struct B {
int i;
};
A a;
a.i = 0;
assert(sizeof(A)==sizeof(B));
我没有看到这个断言可以在符合标准的实现中失败。
答案 2 :(得分:0)
如果你看一下模板,你会注意到这样的“优化”通常最终几乎没有输出,即使模板文件可能有数千行......
我认为你所谈论的优化几乎总是出现在一个函数中,当在堆栈上使用该对象并且该对象没有被复制或传递给另一个函数并且永远不会访问私有字段时(不是甚至初始化......这可能被视为一个错误!)