Why does multiple inheritance increase the size of the object despite the bases being empty?
Asked Answered
H

2

17

Given this code:

#include <iostream>

struct A {

};

struct B {

};

struct C {

};

struct E : A {
    int field;
};

struct F : A, B {
    int field;
};

struct G : A, B, C {
    int field;
};

int main() {
    std::cout << _MSC_VER << std::endl;
    std::cout << sizeof(E) << std::endl;
    std::cout << sizeof(F) << std::endl;
    std::cout << sizeof(G) << std::endl;
    int o;
    std::cin >> o;
    return 0;
}

I am given the following output:

1900
4
8
8

Why would F and G have sizes of 8 even though their bases are empty? And why would the size of E not increase as well?

I am building this with Visual Studio Community 2015, version 14.0.25431.01 Update 3. The MSVC++ version is apparently 9.0.

How come? What rationale is there for such a peculiar memory layout?

Hardening answered 31/10, 2016 at 22:48 Comment(9)
Why should it be a bug? Which language rule do you think the compiler violates?Gerena
@Kerrek If it is not a bug for it does not violate the standard, that answers my question equally well.Hardening
@KerrekSB Maybe the informal rule of "you don't pay for what you don't use". Though it's not in the standard, it would concern me if I thought it was being violated.Grappa
One day you'll grow up and be able to buy yourself your own, better compiler :-)Gerena
I compiled it with clang and g++ and for both cases the output is 4 4 4. So it must be specific to visual c++. As others mentioned though, it's not a bug, it's just a choice of the compiler.Hathcock
Maybe OP should delete the 'could this be a compiler bug' statement so people could focus on the 'how come' part.Wernsman
@MarsonMao I believe you are right. I've edited the last section accordingly.Hardening
@MarsonMao: Absolutely. There are just far too many questions on SO along the lines of "Hey guys I picked up this cool language C\C++ last week, and does my compiler have a bug or what?"Gerena
It is not a "bug" in the sense that it's improperly implemented. EBO must be explicitly requested for now due to a design-tradeoff: allow objects compiled with different versions of VS 2015 to interoperate seamlessly. As for the "language rules" comments, I'm pretty sure these types meet the StandardLayout concept, which enforce EBO since C++11Gorgon
G
2

Visual Studio 2015 Update 2 added support for Empty Base Class Optimization. However, as Updates are supposed to be layout-compatible between them, the optimization is not on by default; you need to manually ask for it using __declspec(empty_bases).

There's more information in VC's blog: https://blogs.msdn.microsoft.com/vcblog/2016/03/30/optimizing-the-layout-of-empty-base-classes-in-vs2015-update-2-3/

This will eventually be the default once they release a major compiler version update, where they're allowed to break binary compatibility.

Gorgon answered 5/11, 2016 at 11:14 Comment(0)
G
10

There is no language rule that says that any particular type needs to have any particular size, with the exception of char (size 1), and subject to the constraint that complete objects of class type have non-zero size. There is nothing buggy about your particular compiler's way of laying out the types in your example.

As for the new question, after you edited it: It's possible that MSVC just doesn't put a lot of effort into optimising multiple inheritance, because that's a comparatively rare thing that you could argue that there's little pay-off. I don't know anything about the real decision process that went on, but just consider that there may be pragmatic engineering trade-offs like this at play.

Gerena answered 31/10, 2016 at 22:54 Comment(1)
The need for empty base class optimization has been reinstated with the introduction of C++/WinRT. It available starting with Visual Studio 2015 Update 2, but it is off by default (like all changes breaking binary compatibility).Antenatal
G
2

Visual Studio 2015 Update 2 added support for Empty Base Class Optimization. However, as Updates are supposed to be layout-compatible between them, the optimization is not on by default; you need to manually ask for it using __declspec(empty_bases).

There's more information in VC's blog: https://blogs.msdn.microsoft.com/vcblog/2016/03/30/optimizing-the-layout-of-empty-base-classes-in-vs2015-update-2-3/

This will eventually be the default once they release a major compiler version update, where they're allowed to break binary compatibility.

Gorgon answered 5/11, 2016 at 11:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.