开发者

Why base classes can have a zero size?

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?


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.


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.


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜