基本上它是this question的一个 * 后续 *。
当我查看标准文档时,我发现了这个。
在第9.3类中,
类类型的完整对象和成员子对象必须具有非零大小。96).
是啊,没错...但是,
96)基类子对象不受如此约束。
所以,当我查看Stroustrup的FAQ时,有一个例子,
void f(X* p)
{
void* p1 = p;
void* p2 = &p->a;
if (p1 == p2) cout << "nice: good optimizer";
}
字符串
我的问题是我不明白这是如何优化以及为什么允许基类的大小为零?
5条答案
按热度按时间5q4ezhmt1#
这是一种优化,因为如果基类子对象的大小必须为非零,则派生类的示例占用的空间会更少。这意味着基类(如接口、mix-ins或模板化策略类)不会增加实现或使用它们的类的大小。最终,您的程序需要更少的内存来做同样的事情。
我不太清楚历史,但我得到的印象是,在20世纪90年代的某个时候,一些编译器开始这样做,标准委员会决定标准化现有的实践。我认为STL模板中分配器对象的激增是部分原因-
std::vector
通常是3个指针的大小,具有空基优化,和4个指针没有它(由于对齐). Here's an article从1997年讨论它-很明显,这是不是所有的广泛编写时,但它基本上是标准的做法现在。lymgl2op2#
基类 * 不能 * 大小为零。只有基类 * 子对象 * 可以。这意味着派生对象的基类部分。
o75abkj43#
如果基类是空的,你将永远不需要基类对象或它的任何成员的地址(独立于派生类对象的地址),所以优化它的大小是法律的。
这为您节省了(至少)一个字节的内存(由于内存对齐规则,可能更多),如果您在内存受限的平台上的应用中有数百万个此类对象,则可以节省大量内存。
rkue9o1l4#
我不是雷蒙德·陈,但我可以玩“如果这是真的”的游戏。
如果一个可以作为引用传递的类可以是零大小,那么在某个时候它可能会被传递给
malloc(0)
,这可能会返回NULL或一个可解引用的地址。然而,如果它是另一个类或基类的成员,它的地址和大小是从它在包含类分配中的位置导出的,并且它的大小为零是安全的。
零大小对内存效率有好处。
093gszye5#
一个对象的大小就是它的成员的累积大小。不,没有一个类的大小可以为零,即使是一个空类也会有1个字节的大小。
这里的意思是
第一个月
对象本身不会占用任何空间,而它的成员会。所以对象的地址可以与它的第一个成员子对象的地址匹配,就像
arrays
一样。这就是优化。而在派生类的情况下,它必须包括基类对象,即使是空的也会消耗1个字节,因此上述优化对派生类无效。