This is largely a repetition of what the other answers have already said, but with a few more references to the ISO C++ standard and some musings about the odd behavior of g++.
The ISO C++11 standard, in section 8.3.4 [dcl.array], paragraph 1, says:
If the constant-expression (5.19) is present, it shall be an
integral constant expression and its value shall be greater than zero.
Your class definition:
class Test
{
int arr[0];
};
violates this rule. Section 1.4 [intro.compliance] applies here:
If a program contains a violation of any diagnosable rule [...], a
conforming implementation shall issue at least one diagnostic message.
As I understand it, if a compiler issues this diagnostic and then accepts the program, the program's behavior is undefined. So that's all the standard has to say about your program.
Now it becomes a question about your compiler rather than about the language.
I'm using g++ version 4.7.2, which does permit zero-sized arrays as an extension, but prints the required diagnostic (a warning) if you invoke it with, for example, -std=c++11 -pedantic
:
warning: ISO C++ forbids zero-size array ‘arr’ [-pedantic]
(Apparently you're also using g++.)
Experiment shows that g++'s treatment of zero-sized arrays is a bit odd. Here's an example, based on the one in your program:
#include <iostream>
class Empty {
/* This is valid C++ */
};
class Almost_Empty {
int arr[0];
};
int main() {
Almost_Empty arr[2];
Almost_Empty x, y;
std::cout << "sizeof (Empty) = " << sizeof (Empty) << "\n";
std::cout << "sizeof (Almost_Empty) = " << sizeof (Almost_Empty) << "\n";
std::cout << "sizeof arr[0] = " << sizeof arr[0] << '\n';
std::cout << "sizeof arr = " << sizeof arr << '\n';
if (&x == &y) {
std::cout << "&x == &y\n";
}
else {
std::cout << "&x != &y\n";
}
if (&arr[0] == &arr[1]) {
std::cout << "&arr[0] == &arr[1]\n";
}
else {
std::cout << "&arr[0] != &arr[1]\n";
}
}
I get the required warning on int arr[0];
, and then the following run-time output:
sizeof (Empty) = 1
sizeof (Almost_Empty) = 0
sizeof arr[0] = 0
sizeof arr = 0
&x != &y
&arr[0] == &arr[1]
C++ requires a class, even one with no members, to have a size of at least 1 byte. g++ follows this requirement for class Empty
, which has no members. But adding a zero-sized array to a class actually causes the class itself to have a size of 0.
If you declare two objects of type Almost_Empty
, they have distinct addresses, which is sensible; the compiler can allocate distinct objects any way it likes.
But for elements in an array, a compiler has less flexibility: an array of N elements must have a size of N times the number of elements.
In this case, since class Almost_Empty
has a size of 0, it follows that an array of Almost_Empty
elements has a size of 0 *and that all elements of such an array have the same address.
This does not indicate that g++ fails to conform to the C++ standard. It's done its job by printing a diagnostic (even though it's a non-fatal warning); after that, as far as the standard is concerned, it's free to do whatever it likes.
But I would probably argue that it's a bug in g++. Just in terms of common sense, adding an empty array to a class should not make the class smaller.
But there is a rationale for it. As DyP points out in a comment, the gcc manual (which covers g++) mentions this feature as a C extension which is also available for C++. They are intended primarily to be used as the last member of a structure that's really a header for a variable-length object. This is known as the struct hack. It's replaced in C99 by flexible array members, and in C++ by container classes.
My advice: Avoid all this confusion by not defining zero-length arrays. If you really need sequences of elements that can be empty, use one of the C++ standard container classes such as std::vector
or std::array
.