7

示例代码

#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

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

4

2 回答 2

3

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

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

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

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

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

  • 5value
  • left<right<left<right<left<base>>>>>

只有 theleft<right<left<right<left<base>>>>>和它的一个主题 the (value如果我记得其他规则的话,第一个)可以共享一个地址。也就是说,对象的大小至少需要为 5。由于对象在对齐时效果最好,它似乎被填充到 6 个字节(这很奇怪;我希望它被填充到 4 的倍数)。

甚至left<base>不可能的大小1:已经涉及两个base对象!一个以基类形式的lef<base> and one in form of a member of this class. These twobase` 对象需要不同的地址,因此,大小至少需要为 2。

无论如何,对象大小只要求它们至少有多大。他们没有任何要求,他们不得大于某物。这被认为是实施质量问题。基于此,唯一错误的编译器(假设大小引号确实是正确的)是 MSVC++。其他尺寸有时可能比期望的稍大,但这不是错误。

于 2012-11-22T06:49:02.400 回答
0

GCC 的行为很奇怪,但 sizeof 完全是编译器问题,所以它只取决于编译器如何说你可以尝试

#pragma pack(1) 

并再次查看结果

于 2012-11-22T06:35:41.410 回答