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.