Reputation: 393
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?
Upvotes: 5
Views: 907
Reputation: 39089
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.
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".
Upvotes: 6
Reputation: 153909
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.
Upvotes: 2
Reputation: 254461
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
).
Upvotes: 8
Reputation: 310970
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.
Upvotes: 1
Reputation: 409176
When you print &b
you print the address of where the variable b
is stored. And yes, this location will be occupied, by that variable. Even if an object have zero size during compilation (remember that sizeof
is a compile-time operator), a variable of that object must be addressable during run-time, and so take up space in memory.
Upvotes: 0