为什么空基类的大小可以为零?
基本上它是这个问题..
当我查看标准文档时,我发现了这个..
在Classes 9.3中,
类类型的完整对象和成员子对象应具有非零大小。96) ...
是的,正确的..但是,
96) 基类子对象没有那么受限。
因此,当我查看 Stroustrup 的常见问题解答时,有一个例子,
void f(X* p)
{
void* p1 = p;
void* p2 = &p->a;
if (p1 == p2) cout << "nice: good optimizer";
}
我的问题是我无法理解它是如何优化以及为什么允许基类的大小为零?
Basically it is a follow up of this question..
When I look into the Standard docs I found this..
In Classes 9.3,
Complete objects and member subobjects of class type shall have nonzero size.96) ...
Yeah, true.. But,
96)Base class subobjects are not so constrained.
So, when I looked into Stroustrup's FAQ, there is an example as
void f(X* p)
{
void* p1 = p;
void* p2 = &p->a;
if (p1 == p2) cout << "nice: good optimizer";
}
My question is I couldn't understand how it is an optimization and also why base classes are allowed to have zero size?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
基类不能具有零大小。只有基类子对象可以。表示派生对象的基础部分。
Base classes cannot have zero size. Only base class subobjects can. Meaning the base part of the derived object.
如果基类为空,则永远不需要基类对象或其任何成员的地址(即独立于派生类对象的地址),因此优化其大小是合法的。
这可以为您节省(至少)一个字节的内存(由于内存对齐规则,可以节省更多),如果您的应用程序在内存受限的平台上有数百万个此类对象,那么这可以节省大量内存。
If the base class is empty, you will never need to have the base class object's or any of its members' address (independent of the derived class objects's address, that is), so it is legal to optimize its size away.
That saves you (at least) one byte of memory (can be more due to memory alignment rules), which can add up to significant savings if you have millions of such objects in your app on a memory-constrained platform.
我不是雷蒙德·陈,但我可以玩“如果这是真的会怎样”的游戏。
如果可以作为引用传递的类的大小为零,那么在某些时候它可能会传递给
malloc(0)
,这可能会返回 NULL 或可取消引用的地址。那么两个实例可能看起来相等,而实际上它们不应该相等。然而,如果它是另一个类或基类的成员,则其地址和大小源自其在包含类分配中的位置,并且其大小为零是安全的。
零大小有利于内存效率。
I'm no Raymond Chen, but I can play the 'what if it were true' game.
If a class that can be passed as reference can be zero-size, then at some point it might be passed to
malloc(0)
, which may return NULL or a dereferencable address. Then two instances could appear equal when they should not.If however it is a member of another class or a base-class, its address and size are derived from its placement in the containing class allocation, and it is safe for it to be zero size.
And being zero size is good for memory efficiency.
对象的大小只不过是其成员的累积大小。
不,任何类的大小都不能为零,即使是空类也有 1 个字节的大小。
这里的
基类子对象不那么受限制。
的意思是对象本身不会消耗任何空间,而是它的成员会消耗任何空间。因此,对象的地址可能与其第一个成员子对象的地址匹配,与
数组
的情况相同。这就是优化。而在派生类的情况下,它必然包含基类对象,即使基类对象为空也会消耗1个字节,因此上述优化对于派生类无效。
Size of an object is nothing but the cumulative size of it's members.
And NO, no class can have a zero size, even an empty class will have a size of 1 byte.
What is meant here by
Base class subobjects are not so constrained.
is that the object itself won't consume any space rather it's members will. So the address of an object may match with that of its first member subobject, same as in case of
arrays
. Thats the optimization.While in case of derived class, it will necessarily include the base class object, which even empty will consume 1 byte, hence above optimization is not valid for a derived class.
这是一种优化,因为派生类的实例占用的空间比基类子对象需要具有非零大小时占用的空间要少。这意味着接口、混合或模板化策略类等基类不会增加实现或使用它们的类的大小。最终,您的程序需要更少的内存来完成同样的事情。
我不太清楚历史,但我得到的印象是,在 20 世纪 90 年代的某个时候,一些编译器开始这样做,标准委员会决定对现有实践进行标准化。我认为 STL 模板中分配器对象的激增是部分原因 - std::vector 通常是 3 个带有空基优化的指针的大小,以及 4 个没有空基优化的指针的大小(由于结盟)。 这里有一篇 1997 年的文章讨论了这个问题 - 很明显,当这篇文章撰写时它还没有那么广泛,但这现在基本上是标准做法。
It's an optimization because instances of the derived class take up less space than they would have, if the base class subobjects were required to have non-zero size. It means that base classes such as interfaces, or mix-ins, or templated policy classes, don't increase the size of classes that implement or use them. Ultimately, your program needs less memory to do the same thing.
I'm not terribly sure on the history, but the impression I get is that sometime in the 1990s, some compilers started doing it, and the standards committee decided to standardize the existing practice. I think the proliferation of allocator objects in STL templates was part of the reason - a
std::vector
typically would be the size of 3 pointers with the empty base optimization, and 4 pointers without it (due to alignment). Here's an article from 1997 discussing it - it's clear that it wasn't all that widespread when that was written, but it's basically standard practice now.