I understand that empty classes in C++ have a size of 1 byte. However, I noticed that sizeof() returns 0 for objects of this class(in g++):
class Boom{
int n[0];
}
I can print a valid memory location for a Boom object:
Boom b;
cout<<&b;
Is this particular memory location occupied? If I allocate memory later in the program, is there a chance that this location will be used?
Although the size of a zero-length array is zero, an array member of this kind may increase the size of the enclosing type as a result of tail padding. The offset of a zero-length array member from the beginning of the enclosing structure is the same as the offset of an array with one or more elements of the same type.
Actually, the standard does not permit objects (or classes) of size 0, this is because that would make it possible for two distinct objects to have the same memory location. This is the reason behind the concept that even an empty class must have a size at least 1. It is known that size of an empty class is not zero.
The size of an empty class is not zero. It is 1 byte generally. It is nonzero to ensure that the two different objects will have different addresses.
C++ allows creating an Empty class, yes! We can declare an empty class and its object. The declaration of Empty class and its object are same as normal class and object declaration.
Arrays cannot have zero size. If your compiler allows you to declare one, then the language doesn't specify how it behaves.
In this case, with this compiler, it does indeed appear that this allows two objects to occupy the same location:
Boom b[2];
std::cout << &b[0] << ' ' << &b[1] << std::endl;
// Output: 0x7fffffb23fdc 0x7fffffb23fdc
But other compilers may behave differently, or simply reject the invalid declaration (as GCC does if you specify -pedantic -Werror
).
A size of 0 is invalid, both for classes and arrays. The C++ standard says:
Sizeof [expr.sizeof]
[...] The size of a most derived class shall be greater than zero [...]
and
Arrays [dcl.array]
In a declaration T D where D has the form
D1 [ constant-expressionopt] attribute-specifier-seqopt
[...] If the constant-expression (5.19) is present, it shall be an integral constant expression and its value shall be greater than zero [...]
If you turn on -pedantic
with g++, you will receive the following warning (or error with pedantic-errors
):
ISO C++ forbids zero-size array ‘n’
so your program is basically not valid, but can be compiled by means of a compiler extension to the C++ standard (unless you turn this extension off).
Note: Even though your compiler can report 0
for the class
, it won't do so for any instance (a.k.a. object) of that class
:
#include <iostream>
class Boom {
int n[0];
};
int main() {
std::cout << sizeof(Boom) << '\n'; // prints 0
std::cout << sizeof(Boom()) << '\n'; // prints 1
}
Having objects of size-0 would go simply too far off the standard.
Citation by Stroustroup:
Why is the size of an empty class not zero?
To ensure that the addresses of two different objects will be different. For the same reason, "new" always returns pointers to distinct objects. Consider:
class Empty { }; void f() { Empty a, b; if (&a == &b) cout << "impossible: report error to compiler supplier"; Empty* p1 = new Empty; Empty* p2 = new Empty; if (p1 == p2) cout << "impossible: report error to compiler supplier"; }
There is an interesting rule that says that an empty base class need not be represented by a separate byte:
struct X : Empty { int a; // ... }; void f(X* p) { void* p1 = p; void* p2 = &p->a; if (p1 == p2) cout << "nice: good optimizer"; }
This optimization is safe and can be most useful. It allows a programmer to use empty classes to represent very simple concepts without overhead. Some current compilers provide this "empty base class optimization".
This is a g++ extension; the C++ standard doesn't allow arrays
of 0
elements. I think that this extension was originally
designed to do what using an incomplete array type as the final
element does in C99, but in C99, it's only legal if the struct
contains more than one member. As for what happens if you
declare an array of Boom
, you'll have to ask g++. (C99 avoids
this issue by requiring at least one other member.)
The only real use for this feature is for variable length dynmamically allocated objects, e.g.:
struct Array
{
size_t size;
int data[];
};
// ...
Array* p = (Array*)malloc(sizeof(Array) + n * sizeof(int));
p->size = n;
(This uses the C standard syntax.)
In C++, we'd normally just use std::vector
and be done with
it.
In this definition
class Boom{
int n[0];
}
there are two errors.:) 1. You forgot to place a semicolon after the closing brace. 2. The size of an array may not be set to zero.
And even empty classes have sizes that are not equal to zero. For example
struct A {};
std::cout << sizeof( A ) << std::endl;
will return a value that greater than 0.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With