Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Empty struct and anonymous union weird case

Compiling my code as C++11 with gcc 4.8.2 and llvm/clang 3.4 on fedora-linux, I got strange results that I couldn't really explain... here is a similar program fedora.

#include <iostream>
using namespace std;

struct A {};
struct C {};
struct B1 : A { union { A a;}; };
struct B2 : A { union { C c;}; };

int main()
{
    cout << sizeof(B1) << " " << sizeof(B2) << endl;
}

sizeof(B1) = 2 and sizeof(B2) = 1

But why are the sizes different? Actually I have an idea "why", but I want to find the exact explanation or C++ rule.

like image 229
user3608817 Avatar asked May 06 '14 15:05

user3608817


3 Answers

The B1 child has both a parent and sub-object of type A. Two distinct objects of the same type cannot exist at the same address, and the union separately contains an additional A to the parent A.

With B2, the empty base optimization allows the empty A parent and C member to share the single address of the child.

like image 145
Mark B Avatar answered Nov 14 '22 23:11

Mark B


I think that there will be helpful two quotes from the C++ Standard. The first one defines what is subobject.

2 Objects can contain other objects, called subobjects. A subobject can be a member subobject (9.2), a base class subobject (Clause 10), or an array element.

The second one says that two subobjects of the same type may not have the same address

A base class subobject may be of zero size (Clause 9); however, two subobjects that have the same class type and that belong to the same most derived object must not be allocated at the same address (5.10). —end note ]

So in this class definition

struct B1 : A { union { A a;}; };

there are two subobjects of type A: base class subobject and member subobject a.

Also it is important to add that every member of every anonymous union is a member of the class containing the anonymous unions.

like image 27
Vlad from Moscow Avatar answered Nov 14 '22 22:11

Vlad from Moscow


The C++11 standard can be interpreted to allow size 1 for both examples:

1.8 The C++ object model §6:

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 distinct objects that are neither bit-fields nor base class subobjects of zero size shall have distinct addresses.

There's at least one non-normative notice disallowing it for case 1, but it is non-normative:

10 Derived classes §8:

[ Note: A base class subobject might have a layout (3.7) different from the layout of a most derived object of the same type. A base class subobject might have a polymorphic behavior (12.7) different from the polymorphic behavior of a most derived object of the same type. A base class subobject may be of zero size (Clause 9); however, two subobjects that have the same class type and that belong to the same most derived object must not be allocated at the same address (5.10). —end note ]

The latest publicly available draft (n3797 dated 2013-10-13) though disallows the first example to have size 1:

1.8 The C++ object model §6:

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 that are not bit-fields may have the same address if one is a subobject of the other, or if at least one is a base class subobject of zero size and they are of different types; otherwise, they shall have distinct addresses.

like image 1
Deduplicator Avatar answered Nov 14 '22 23:11

Deduplicator