示例代码
#include <iostream>
struct base {};
template<typename Type>
struct left : base {
Type value;
};
template<typename Type>
struct right : base {
Type value;
};
int main() {
std::cout << "sizeof left<base> = " << sizeof(left<base>) << std::endl;
std::cout << "sizeof left<right<base>> = " << sizeof(left<right<base>>) << std::endl;
std::cout << "sizeof left<right<left<right<left<base>>>>> = " << sizeof(left<right<left<right<left<base>>>>>) << std::endl;
}
输出
GCC 4.6是
sizeof left<base> = 2
sizeof left<right<base>> = 3
sizeof left<right<left<right<left<base>>>>> = 6
使用clang 3.1
sizeof left<base> = 2
sizeof left<right<base>> = 3
sizeof left<right<left<right<left<base>>>>> = 6
使用MSVC 2012
sizeof left<base> = 1
sizeof left<right<base>> = 1
sizeof left<right<left<right<left<base>>>>> = 1
所以,问题是,它是GCC / clang中的错误,还是它是实现定义的,还是正确的输出(来自标准的引用,或者对这种行为的解释会很好)
答案 0 :(得分:3)
相关引用是1.8 [intro.object]第6段:
除非对象是零字段或零大小的基类子对象,否则该对象的地址是它占用的第一个字节的地址。如果一个是另一个的子对象,或者如果至少一个是零大小的基类子对象并且它们是不同类型的,则不是位字段的两个对象可以具有相同的地址;否则,他们应有不同的地址。
在您的right<T>
和left<T>
对象中(为什么要使用不同的类模板?一个应该已经足够了)您每个人都有一个成员value
(类型为T
) 。每个人都需要获得自己独特的地址。因此,
sizeof(left<right<left<right<left<base>>>>>) == 1
绝对错了!有6个不同的对象:
value
s left<right<left<right<left<base>>>>>
只有left<right<left<right<left<base>>>>>
及其中一个主题(如果我记得其他规则,第一个value
)可以共享一个地址。也就是说,对象的大小至少需要为5.由于对象在对齐时效果最好,它似乎填充到6个字节(这很奇怪;我希望它被填充到4的倍数)。 / p>
即使left<base>
的大小也不能1
:已经涉及两个base
个对象!一个lef<base> and one in form of a member of this class. These two
base`对象的基类形式需要不同的地址,因此,大小至少需要2个。
在任何情况下,对象大小只要求它们至少有多大。他们没有任何要求他们不应该大于某些东西。这被认为是实施质量问题。基于此,唯一的编译器错误(假设大小引号确实是正确的)是MSVC ++。其他尺寸有时可能略大于预期,但这不是错误。
答案 1 :(得分:0)
GCC的行为很奇怪,但sizeof完全是编译器问题,因此它仅取决于编译器的说法 你可以尝试
#pragma pack(1)
再次查看结果