为什么空基类的大小可以为零?

问题描述 投票:0回答:5

基本上是这个问题的后续..

当我查看标准文档时,我发现了这个..

9.3 班

类类型的完整对象和成员子对象应具有非零大小。96) ...

是的,没错..但是,

96)基类子对象没有那么受限

所以,当我查看Stroustrup的常见问题解答时,有一个例子

void f(X* p)
    {
        void* p1 = p;
        void* p2 = &p->a;
        if (p1 == p2) cout << "nice: good optimizer";
    } 

我的问题是我无法理解它是如何优化的以及为什么允许基类的大小为零

c++ compiler-optimization base-class empty-class
5个回答
11
投票

基类不能的大小为零。只有基类子对象可以。意思是派生对象的基础部分。


10
投票

如果基类为空,您将永远不需要基类对象或其任何成员的地址(即独立于派生类对象的地址),因此优化其大小是合法的。

这可以为您节省(至少)一个字节的内存(由于内存对齐规则,可能会更多),如果您的应用程序在内存受限的平台上有数百万个此类对象,那么这可以节省大量的内存。


0
投票

我不是 Raymond Chen,但我可以玩“如果这是真的会怎样”的游戏。

如果可以作为引用传递的类可以为零大小,那么在某些时候它可能会被传递到

malloc(0)
,这可能会返回 NULL 或可取消引用的地址。那么两个实例可能看起来相等,但它们不应该相等。

但是,如果它是另一个类或基类的成员,则其地址和大小源自其在包含类分配中的位置,并且其大小为零是安全的。

零大小有利于内存效率。


0
投票

对象的大小只不过是其成员的累积大小。 不,任何类的大小都不能为零,即使是空类的大小也将为 1 字节。

这里的

是什么意思

Base class subobjects are not so constrained.

对象本身不会消耗任何空间,而是它的成员会消耗任何空间。因此,对象的地址可能与其第一个成员子对象的地址匹配,与

arrays
的情况相同。这就是优化。

而对于派生类,它必然包含基类对象,即使为空也会消耗 1 个字节,因此上述优化对于派生类无效。


0
投票

这是一种优化,因为如果基类子对象需要具有非零大小,则派生类的实例占用的空间比它们占用的空间要少。这意味着接口、混合或模板化策略类等基类不会增加实现或使用它们的类的大小。最终,您的程序需要更少的内存来完成同样的事情。

我不太清楚历史,但我得到的印象是,在 20 世纪 90 年代的某个时候,一些编译器开始这样做,标准委员会决定对现有实践进行标准化。我认为 STL 模板中分配器对象的激增是部分原因 -

std::vector
通常是具有空基优化的 3 个指针的大小,以及没有空基优化的 4 个指针的大小(由于对齐)。 这里有一篇 1997 年的文章 对此进行了讨论 - 很明显,当这篇文章撰写时,它还没有那么广泛,但现在它基本上是标准做法。

© www.soinside.com 2019 - 2024. All rights reserved.