Re: question about empty class
On Apr 6, 2:34 am, goodbye...@gmail.com wrote:
I once read from some text book that an empty class like:
class A {};
won't get 0 when the sizeof operator is applied to it. Usually the
compiler would generate an internal char member for it (though
accessing this member would be undefined behaviour) so that sizeof(A)
would be 1. One reason to do this is to make sure no 2 objects of
class A would have the same address.
So for the following class hierarchy:
class AAA {};
class BBB: public virtual AAA {};
class CCC: public virtual AAA {};
class DDD: public BBB, public CCC {};
for class BBB/CCC/DDD, since some internal member is already generated
in support for the virtual inheritance mechanism, the AAA subobject in
the derived class object would be of size 0, there is no need for that
compiler-generated char member. So in VC/GCC:
sizeof(AAA) == 1
sizeof(BBB) == sizeof(CCC) == 4
sizeof(DDD) == 8
But the problem is that, in some implementations, this 0-sized AAA
subobject would be placed at the end of the derived class object, so
given the following code fragment:
int main() {
DDD d[2];
AAA* pa = &d[0];
if ((void*)pa == (void*)&d[1])
cout << "wow!";
return 0;
}
it will output "wow!" in VC, that is, pointers to two different
objects compares equal...
GCC does this differently. When a virtual base class is not an empty
class, it does the same as VC placing the virtual base class subobect
at the end of the derived class object; But when the virtual base
class is an empty class as AAA, it will place the 0-sized virtual base
class subobject at the beginning of the derived class object, so the
above problem won't happen.
So, my question is, can this considered to be a bug of VC? Or the
standard doesn't imply any requirement on this so basically any
implementation approach is simply fine?
The Standard imposes the following requirement (10[class.derived]/5):
"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)."
So it would seem that VC implementation still satisfies that
requirement; and I can't find any more restrictive ones...
At the same time, it is clear that the rationale for no zero-sized
objects here is violated. Note that in your example, we're comparing
void* pointers; if we cast both sides to AAA* first, the comparison
would go "normally". However, it seems that it would be possible to
get the same result even for AAA* pointers, and without casts, on a
given implementation. For example, consider this:
#include <iostream>
using namespace std;
class AAA {};
class BBB: public virtual AAA {};
class CCC: public virtual AAA {};
class DDD: public BBB, public CCC {};
struct foo { DDD d; AAA a; };
int main() {
foo f;
if (&f.d == &f.a)
cout << "wow!";
return 0;
}
VC also prints "wow" for me here with default alignment options. But
this case looks far more sinister, since there aren't even any casts
involved at all, and clearly f.d and f.a are two different objects...
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]