【问题标题】:Why is the size of an empty class in C++ not zero? [duplicate]为什么 C++ 中空类的大小不为零? [复制]
【发布时间】:2011-01-22 15:45:03
【问题描述】:

可能重复:
C++: What is the size of an object of an empty class?

为什么下面会输出1

#include <iostream>

class Test
{
};

int main()
{
    std::cout << sizeof(Test);
    return 0;
}

【问题讨论】:

  • 有一个虚拟占位符成员,其大小恰好是一个字节。因为对于 Test[10] 的数组,每个对象都应该有一个唯一的地址。
  • 一个有趣的优化是Empty Base Optimization,这意味着如果你从一个空的基类(没有属性,没有虚拟方法)继承,那么你的类大小不会增长。有许多(其他)条件,但它解释了为什么在某些情况下从谓词私下继承。

标签: c++ sizeof


【解决方案1】:

确保两个地址 不同的对象会有所不同。 出于同样的原因,“新”总是 返回指向不同对象的指针。

完整答案请见Stroustrup

【讨论】:

    【解决方案2】:

    C++ 标准保证任何类的大小至少为 1。 C++ 标准规定,任何对象都不得与另一个对象具有相同的内存地址。这有几个很好的理由。

    1. 保证new 将始终返回指向不同内存地址的指针。

    2. 为了避免某些除以零。例如,指针算术(其中许多由编译器自动完成)涉及除以sizeof(T)

    但是请注意,这并不意味着空的基类会将派生类的大小加 1:

    struct Empty { };
    
    struct Optimized : public Empty {
        char c;
    };
    
    // sizeof(Optimized) == 1 with g++ 4.0.1
    

    Bjarne Stroustrup talks about this 也是。

    【讨论】:

    • 什么指针运算涉及到除以sizeof(T)?我想不出一个例子。请添加至少一个示例。
    • @MSalters:迭代 T 类型元素的数组。
    • @MSalters:两个指针相减返回的是元素数,而不是字节数。
    • @Ben Voigt:好点,你是对的。遍历数组只是意味着 添加 sizeof(T) 字节到指针,但内部的指针差异将首先计算为字节差异。
    【解决方案3】:

    没有任何数据成员和成员函数的类,这种类型的类称为空类。空类对象的大小始终为 1 字节。

    当我们创建任何类的对象时,对象总是获得 3 个特征,即

    1. 状态
    2. 行为
    3. 身份

    当我们创建空类的对象时,那个对象的状态是什么。该对象的行为也没什么,但是编译器为该对象分配了一个唯一的地址。 计算机中的内存始终以字节的形式组织,对象地址位置的最小可用内存为 1 个字节。这就是为什么空类的对象大小是 1 字节的原因。

    【讨论】:

    • 如果有人想知道一个对象的 3 个特性,即 1) 状态 2) 行为 3) 身份然后问我
    【解决方案4】:

    毛里茨和彼得说了什么。

    有趣的是,在这种情况下,编译器可以进行空基类优化 (EBCO):

    #include <iostream>
    struct Foo {};
    struct Bar : Foo {};
    int main () {
        std::cout << sizeof(Foo) << ',' << sizeof(Bar) << std::endl;        
    }
    

    如果您编译并运行它,这可能会打印“1,1”。另请参阅 EBCO 上的 Vandevoorde/Josuttis 16.2

    【讨论】:

      【解决方案5】:

      该标准不允许大小为 0 的对象(及其类),因为这会使两个不同的对象具有相同的内存地址成为可能。这就是为什么即使是空类也必须具有(至少)1 的大小。

      【讨论】:

      • 嗯...但是无论 sizeof() 返回什么,链接器都不应该处理这个问题吗?这不是更像是副作用吗?我明白你在说什么,但是为 sizeof(Test) 返回 0 不是完全可行的吗?但如果标准是这样说的,它就是这样说的。实际上,一次明确而不是故意模糊一个主题是一件好事。
      • @Amigable,那么Test a[10]; 的大小是多少?而sizeof a / sizeof *a 将除以 0。for(Test *i = a; i != a + 10; i++) f(i); 也将无法工作。我相信这会导致很多问题,因为您需要在编译器中在用户代码中使用很多特殊情况。
      • @Johannes,确实如此。我没想到。
      • @JohannesSchaub-litb:我不同意你的评论。 sizeof a / sizeof *a 将为 0/0,这对于零大小类型来说是一致且“正确”的行为(这是因为无法区分 Test a[10] 和 Test a[100],这是合乎逻辑的,因为它们是都退化})。 for 循环也不会失败。这是因为 a + 10 = a。我没有看到任何与零大小类型的逻辑不一致,IMO 不允许它们引入不一致。这样做的唯一优势可能只是要求所有对象都有不同的地址。
      • @AndreasH.:我基本同意你的观点,我认为sizeof(Empty) 应该为零。但它有点复杂,因为for(Test *i = a; i != a + 10; ++i) f(*i); 会做与for(int i = 0; i &lt; 10; ++i) f(a[i]) 不同的事情。我在Legalization of empty objects 详细分析了它,包括提出的解决方案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-10
      • 1970-01-01
      相关资源
      最近更新 更多