c++genericsinheritancesizeofempty-class

What is the size of a derived class if a base class has no members?


Consider the following inheritance:

class Base {
protected:
  Base() { }
public:
  double Multiply(double x);
};

class Derived : public Base {
  double _value;
public:
  Derived(double init) : _value(init) { }
  double Multiply(double x) { return x*_value; }
};

This code piece is to be used in templated codebase. Polymorphism is not an option because it adds VTable pointer thus doubles the memory consumption.

However, I suspect that because of C++ requirement for objects to have size at least 1 byte, the size of Derived would become 9 bytes and, consequently, because of padding/alignment it will further become 16 bytes.

So is there a way in C++ to keep the size of Derived equal to the size of double (usually 8 bytes) ? What does the standard say about the size of Derived? Particularly, how does MSVC++ behave in this case?


Solution

  • This is called Empty base optimization, it is defined in standard as following:

    1.8 The C ++ object model [intro.object]

    7 Unless it is a bit-field (9.2.4), a most derived object shall have a nonzero size and shall occupy one or more bytes of storage. Base class subobjects may have zero size. An object of trivially copyable or standard-layout type (3.9) shall occupy contiguous bytes of storage.

    8 Unless an object is a bit-field or a base class subobject of zero size, the address of that object is the address of the first byte it occupies. Two objects a and b with overlapping lifetimes that are not bit-fields may have the same address if one is nested within the other, or if at least one is a base class subobject of zero size and they are of different types; otherwise, they have distinct addresses.

    In your example inheriting Base class does not affect the size of the Derived class. However MSVC++ performs such optimization only for a first empty base class so inheriting from addition empty base classes will lead to growth of Derived class size. I believe this has been a point of critisim towards MSVC++ for a long time, as many other compilers don't have this issue. This can be really troublesome if you have a lot of small auxiliary classes. As a workaround a deriving template base class could be used to convert multiple inheritance into a chain of single inheritance:

    class Base1
    {};
    
    template< typename TBase > class Base2: public TBase
    {};
    
    template< typename TBase > class Base3: public TBase
    {};
    
    class Derived: public Base3< Base2< Base1 > >
    {};
    

    MS Connect bug page. It looks like they aren't aiming to fix it after all.