简体   繁体   中英

Zero-sized struct

According to the C++ standard (inherited from C) empty structs have a non-zero size nevertheless. The reason for this (pitiful IMHO) is that two distinct variables should have different addresses. Now, inheriting an empty struct does not always "inflate" the object. But in some situations this is the case.

I have a pretty sophisticated classes architecture, involving fierce template voodoo. As the result the final classes (instances of which I need to create) may have several empty structs inherited. Due to this fact part of them may be inflated eventually. And the worst part is that their memory layout actually depends on the order of inheritance.

I'd like to get rid of all this, if it's possible.

Is there a C++ compiler that can be configured to eliminate this space waste, in expense of breaking the standard actually?

Edit:

I mean this:

struct Empty1 {};
struct Empty2 {};

struct NonEmpty {
    int Value;
};

struct MyClass1
    :public NonEmpty
    ,public Empty1
    ,public Empty2
{
};

struct MyClass2
    :public Empty1
    ,public NonEmpty
    ,public Empty2
{
};

struct MyClass3
    :public Empty1
    ,public Empty2
    ,public NonEmpty
{
};

STATIC_ASSERT(sizeof(MyClass1) == 8);
STATIC_ASSERT(sizeof(MyClass2) == 4);
STATIC_ASSERT(sizeof(MyClass3) == 8);

Not only empty structs inflate the object (when more than one such a thing inherited), but also the result depends on the order of inheritance of the empty structs.

The Empty Base Optimization is what will allow an empty base to not "inflate" the object, as you call it. However, you must be careful so that an object does not inherit from the same empty base twice or this optimization won't be allowed. A way to avoid this is to template the empty bases, instantiating them so that no same empty template instantiation will be inherited more than once.

If your base classes are used to tag concrete classes, then you could consider changing your design to a non-intrusive one.

You will find, in most modern c++ compilers that:

struct a { }; // empty struct
struct b : a { int x}; // inherits from empty struct.

assert(sizeof(b)==sizeof(int)); // despite sizeof(a) >0

Does that, practically, assuage your concerns?

Is there a C++ compiler that can be configured to eliminate this space waste, ...

Yes. gcc-4.3.4

... in expense of breaking the standard actually?

No, the standard allows your desired behavior.

g++ supports zero size arrays, you can use one of:

struct Empty1 {
  int dummy[0];
};

or

struct Empty2 {
  int dummy[];
};

It generates warning, only if the '-pedantic' flags is used.

A base class can be of non-zero size if, as you already stated, it would otherwise have the same address as another instance of the same type in the same object.

To "solve" this problem, you need to ensure that the empty classes or structs you inherit another class from do not have any ancestors in common.

Or you can manually lay out the class yourself, but it sounds like you are doing something like creating a DirectX vertex type from the DirectX vertex declaration enumeration, so that wouldn't really help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM