0

Well, I've encountered a curious behavior in C++, MSVC compiler.

If you write

struct Class1 {};
struct Class2 : Class1 {};
struct Class3 : Class2 {};
struct Class4 : Class3 {};

a sizeof(Class4) will return 1, a expected. But if instead you write

struct Class1 {};
struct Class2 {};
struct Class3 {};
struct Class4 : Class1, Class2, Class3 {};

the sizeof(Class4) will be two in run-time. IntelliSense and constexpr auto x = sizeof(Class4) will indicate a value of 1, but doing some template tricks I've encountered that it report greater than 1 values, and they did not even match to what the actual runtime value is.

Reading a forum I've found this:

If you inherit from an empty class but the compiler’s ABI does not allow that class to overlap its layout with other parts of the class, the class will also increase in size due to pure padding. Consider the C++20 (forthcoming) attribute [[no_unique_address]] as an alternative.

Which I knew, but I still find weird that behavior changes depending on which inheritance implementation I use. Any thoughts on this matter?

EDIT:

For the minimal reproducible example:

// "Sequential" inheritance
struct S0 {};
struct S1 : S0 {};
struct S2 : S1 {};

struct S3 : S2 {

    int val;
    int foo() { return val; }
};

// "End" inheritance
struct E0 {};
struct E1 {};
struct E2 {};

struct E3 : E0, E1, E2 {

    int val;
    int foo() { return val; }
};

int main() { 

    S3 s = S3();
    E3 e = E3();

    std::cout << sizeof(s) << "\n" << sizeof(e) << "\n" << (sizeof(s) == sizeof(e));
    return 0;
}

Which prints out

4
8
0

So an instance of class S3 has a sizeof 4, but an instance of E3 has a sizeof 8. And the ultimate question is why. Why does this two classes, S3 and E3, have a different size depending on the way the inheritance is made?

EDIT 2:

Almost forgot, what i meant by run-time and compile time is, although the program execution return those values, if below previous code you add

constexpr auto sizS3 = sizeof(S3);      // IntelliSense report 4, prints 4
constexpr auto sizE3 = sizeof(E3);      // IntelliSense report 4, prints 8
constexpr auto equal = sizS3 == sizE3;  // IntelliSense report true, prints false (0)

IntelliSense will report both values to be 4U, but printing those values is the same as printing instances S3 s and E3 e.

Solution:

So, after researching more, found this question: Why is the empty base class optimization (EBO) is not working in MSVC?

struct __declspec(empty_bases) E3 : E0, E1, E2 {

    int val;
    int foo() { return val; }
};

Will work as expected.

  • 1
    `sizeof(Class4)` is definitely not a runtime value, there are no runtime classes. Please post a [mcve]. – Quimby Dec 13 '20 at 11:31
  • Can you also reformulate the question so it'll be possible to give a definite answer? – Ted Lyngmo Dec 13 '20 at 11:32
  • To quote Fred Picker, "Different isn't the same". If you change the definition of a class it's size might change, too. – Pete Becker Dec 13 '20 at 14:38
  • I have updated the question, thanks for your time! – Frithu Sama Dec 13 '20 at 20:38
  • IntelliSense and the actual executable disagreeing is not a difference between compile-time and runtime. It's IntelliSense being buggy. The *actual* compiler at *actual* compile-time must be seeing the difference, or else the executable, which it is responsible for creating, will not see a difference. – HTNW Dec 13 '20 at 20:56
  • Well, we all know that IntelliSense is buggy, but that does not explains why the difference in size to the actual compiler. – Frithu Sama Dec 13 '20 at 21:11

0 Answers0