两个模板类型的sizeof,两者都来自一个基础

时间:2012-11-22 06:05:43

标签: c++ c++11

示例代码

#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中的错误,还是它是实现定义的,还是正确的输出(来自标准的引用,或者对这种行为的解释会很好)

2 个答案:

答案 0 :(得分:3)

相关引用是1.8 [intro.object]第6段:

  

除非对象是零字段或零大小的基类子对象,否则该对象的地址是它占用的第一个字节的地址。如果一个是另一个的子对象,或者如果至少一个是零大小的基类子对象并且它们是不同类型的,则不是位字段的两个对象可以具有相同的地址;否则,他们应有不同的地址。

在您的right<T>left<T>对象中(为什么要使用不同的类模板?一个应该已经足够了)您每个人都有一个成员value(类型为T) 。每个人都需要获得自己独特的地址。因此,

sizeof(left<right<left<right<left<base>>>>>) == 1

绝对错了!有6个不同的对象:

  • 5 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) 

再次查看结果

相关问题