tags:

views:

215

answers:

4

Two quotes from the C++ standard, §1.8:

An object is a region of storage.

Base class subobjects may have zero size.

I don't think a region of storage can be of size zero. That would mean that some base class subobjects aren't actually objects. Opinions?

A: 

The base class does not contribute to the size of objects of derived types. A subobject is not an object.

This is called "Empty Base Optimisation" (EBO) and is optional for a compiler to implement.

Eddy Pronk
"Objects can contain other objects, called subobjects."
Johannes Schaub - litb
+4  A: 

C++ does not allow an object of size zero, because every object must have a unique memory address. So if you have:

struct empty {};

// ...

empty myempty;
empty* ptr = &myempty;

then ptr must be pointing to a unique memory address. The standard states the minimum size for an object is 1 byte for this purpose. Similarly, allocations of size 0 are allowed, and return a valid pointer, even if writing to that pointer is not allowed (this works for malloc(0), and new empty returns a pointer to one byte, since sizeof(empty) == 1).

If I derive from empty like so:

struct derived : public empty
{
    int data;
}

There is no longer any point in the base class empty occupying one byte, because all derived will have a unique address due to the data member. The quote "Base class subobjects may have zero size" is present to allow, in this case, for the compiler to not use any space for empty, such that sizeof(derived) == 4. As the title states, it's just an optimization, and it is perfectly legal for the empty part of derived to occupy zero space.

AshleysBrain
Actually `sizeof(empty)` is allowed to be larger, and most compilers are going to make it at least the machine word width.
Billy ONeal
+5  A: 

A philosophical argument over the definition of "region" is unnecessary.

1.8/5 says, "Unless it is a bit-field, a most derived object shall have a non-zero size ... Base class sub-objects may have zero size".

So the standard is quite clear what objects (and hence what "regions of storage") can have zero size. If you disagree with the standard what "region" means in English that's one thing, you can fault the authors' (non-programming-related) literary skills. For that matter you can fault their poetic skills (14.7.3/7) But it's quite clear what the standard says here about the sizes of objects of class types.

The pragmatic way to read standards is that given two plausible interpretations of a word, choose the one which doesn't directly contradict another sentence in the same section of the standard. Don't choose the one which matches more closely your personal preferred use of the word, or even the most common use.

Steve Jessop
"Unless it is a bit-field, a most derived object shall have a non-zero size" seems to conflict with `new int[0]` which is said to "allocate an array with no elements". Does that imply that arrays actually *do* contain internal padding in that case?
Johannes Schaub - litb
I don't think that an array is a most-derived object. 1.8/4: "If a complete object ... is of class type, it's type is considered the most-derived class ... an object of a most derived class type is called a most derived object"
Steve Jessop
@Steve it says "an object of a most derived class type or of a non-class type is called a most derived object". - Edit: C++03 wording seem to differ from the FCD wording.
Johannes Schaub - litb
@Johannes: not in my copy, although I'm prepared to believe that other versions differ, or even that there's a second conflicting definition of most derived object somewhere else.
Steve Jessop
@Steve however i think the intent of C++03 is to include non-class types in the definition "most derived class type", otherwise the prefix "Unless it is a bit-field, ..." prefix would not make sense.
Johannes Schaub - litb
True, that's a difficult one to resolve. No built-in fundamental type can be of size 0 anyway, because they all must be capable of representing at least 2 values. So it doesn't need stating in 1.8 whether they can be zero size or not. Interesting point about aggregates under the revised definition: is there then a contradiction in C++0x, which C++03 arguably avoided completely by accident?
Steve Jessop
Gotta love 14.7.3/7! +1 just for that.
Konrad Rudolph
@Konrad: I don't think I've ever read that part of the standard through, I found it because one day looking up something else I spotted "immolation, self" in the index :-)
Steve Jessop
A: 

The C++ standard 1.8.5 states :-

Unless it is a bit-field (9.6), a most derived object shall have a non-zero size and shall occupy one or more bytes of storage. Base class subobjects may have zero size. An object of trivially copyable or standard-layout type (3.9) shall occupy contiguous bytes of storage.

So, the standard alows a base-class that has no data members (and no virtuals) to share the same address as another subobject with a distinct type. You can play around with the empty base class size like ...

struct a{}; 
struct a1{}; 
struct b : public a, public a1{char c;}; 


int main() 
{ 
  std::cout << sizeof(b) << "\n"; 
  std::cout << sizeof(b::a); 
} 


Which outputs (ignoring padding)...

1 
1 


now try: 


struct a{}; 
struct b : public a {a ax;}; 


int main() 
{ 
  std::cout << sizeof(b) << "\n"; 
  std::cout << sizeof(b::a); 
} 


and the output is ...

2 
1 

because the two instances of a (as a base and as a member) must have distinct addresses.

BTW: "b::a" is another way to say "a". The presence of the scope access operator does not request the "base-class subobject of b of type a". Verse 5.3.3/2 says :- When applying sizeof to a base class subobject, the result is the size of that object's type.

Abhay