Why is the size of an empty class that results from two empty classes equal to 2?

I know that the size of an empty class is 1 to comply with a standard that does not allow objects (and their classes) to be 0. Here I get the size of the derived class D as 2. Why is the behavior different in this case? given that there is no item or virtual pointer inherited from classes B and C to D?

#include<iostream>
using namespace std;

class A {};
class B : public A {};
class C : public A {};
class D : public B, public C {};

int main() {
    cout<<"Size of D is: "<<sizeof(D)<<endl;
    return 0;
}

      

+3


source to share


2 answers


It seems to me that empty base optimization can be applied here or not, depends on how you interpret [intro.object / 8] :

If the object is not a bit field or base class subobject equal to zero size, the address of this object is the address of the first byte it takes. Two objects a and b with overlapping lifetimes that are not bit fields can have the same address if one of them is nested within the other, or if at least one is a zero-size base class subobject and they are of different types ; otherwise they have different addresses.

Are there B

also C

different types? They both are A

. There are actually two different objects A

. The compiler author is allowed to stop the allocated storage right there for B

and C

separately, without checking that it is A

empty.



It's worth noting that with g ++, the size falls back to 1 if you have B

and C

inherit from separate bases:

#include<iostream>

class A  {};
class A1 {};
class B : public A {};
class C : public A1 {};
class D : public B, public C {};

int main() {
    std::cout << "Size of D is: " << sizeof(D) << std::endl;
    return 0;
}

      

+3


source


This is because you inherit from two base classes that were themselves derived from the same base class A

, see how the result changes when you change your program to

#include<iostream>
using namespace std;

class A {};
class Z {};
class B : public A {};
class C : public Z {};
class D : public B, public C {};

int main() {
    cout<<"Size of D is: "<<sizeof(D)<<endl;
    return 0;
}

      

As you can see, the size D

is1

The problem is similar to that of the ugly diamond you probably know about. The compiler is trying to eliminate the two instances A

present D

in your example. And empty base optimization is not applied here, the standard does not require it, and the compiler does not implement it (see below).




The standard explicitly allows compilers not to use empty base optimizations for multiple inheritance cases. Relevant quote from the standard here

Giving classes a standard layout to base classes forces compilers to implement empty base optimizations for standard layout classes, and this can break the compiler application binary interface (ABI). See 9.2 / 18 above. It is believed that this is not a problem with modern compilers, except perhaps in the case of multiple inheritance. Since multiple inheritance is not central to this proposal, allowing standard layout classes or their bases to use multiple inheritance will be excluded from the proposal if it turns out to be controversial.

+2


source







All Articles