[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]
struct X {
int y;
float f;
};
struct Y{
int y;
float f;
};
are required to be layout compatible (for compatibility with C)
struct Z {
public: int y;
public: float f;
};
Does not need to be layout compatible. The compiler may re-order data
members that have been declared with different (though possibly
identical) access specifiers.
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
And the Standard (s.9.2(12)) says:
Nonstatic data members of a (non-union) class declared without an
intervening access-specifier are allocated so that later members have
higher addresses within a class object. The order of allocation of
nonstatic data members separated by an access-specifier is unspecified
(11.1). Implementation alignment requirements might cause two adjacent
members not to be allocated immediately after each other; so might
requirements for space for managing virtual functions (10.3) and
virtual base classes (10.1).
-- Ron
So what about:
struct X {
int y;
float f;
public: int z;
};
Are the order of y and f guranteed and are they guranteed to be at the
start of the struct? Or are all bets off once any explicit access
signifiers are added to the declaration?
Sean
[ ... ]
> > struct Z {
> > public: int y;
> > public: float f;
> > };
> >
> > Does not need to be layout compatible. The compiler may re-order data
> > members that have been declared with different (though possibly
> > identical) access specifiers.
>
> So what about:
>
> struct X {
> int y;
> float f;
> public: int z;
> };
>
> Are the order of y and f guranteed and are they guranteed to be at the
> start of the struct? Or are all bets off once any explicit access
> signifiers are added to the declaration?
Francis is a very smart guy, so I'm extremely hesitant to disagree
with him, but by my reading, he's wrong this one. According to 9/4:
A POD-struct is an aggregate class that has no non-volatile
data members of type pointer to member, non-POD-struct, non-
POD-union (or array of such types) or reference, and has no
user-defined copy assignment operator and no user-defined
destructor.
According to 8.5.1/1:
An aggregate is an array or a class (clause 9) with no user-
declared constructors (12.1), no private or protected non-
static data members (clause 11), no base classes (clause 10)
and no virtual functions (10.3).
Note that this does _not_ say anything about access specifiers --
only about the actual access itself. You're free to use the public
access specifier as often as you wish, and the class remains POD.
Now, if you had something that was NOT a POD-struct, _then_ you'd
have to look at 9.2/12, which says:
... The order of allocation of non-static data members
separated by an access-specifier is unspecified (11.1).
However, since what you declared IS a POD-struct, the implementation
is required to follow 9.2/17, which says:
A pointer to a POD-struct object, suitably converted using
a reinterpret_cast, points to its initial member...
As such, the compiler _must_ arrange your struct so that y is at the
very beginning of the struct. After that must come f (possibly
separated by some padding) and finally z. Francis's example is
similar -- if you start with a pointer to struct Z, and
reinterpret_cast it to int*, it _must_ point to Z::y; the compiler is
NOT allowed to rearrange the layout to place Z::f before Z::y.
I don't think the rules on POD structs are quite strong enough to
ensure what was really originally intended though. Given a
declaration like:
struct A {
public: int x;
public: int y;
public: int z;
};
The compiler can put the members either in of two possible orders: x-
y-z OR x-z-y. Both of these satisfy the requirement in 9.2/17 but
the latter uses the permission in 9.2/12 to rearrange members other
than the first one even though it's clearly a POD-struct (to which I
don't believe this permission was really intended to apply).
--
Later,
Jerry.
The universe is a figment of its own imagination.
I have not got time to check the standard but I believe that it requires
that
&y < & f
I have some recollection that it also requires that
for
X x;
static_cast<char *>(&y) == static_cast<char *>(&x)
But I think it places no requirement on z, and I think that it is
allowed to place z so that:
&y < &z < &f
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
Actually what makes me appear so smart is that I try to learn from my
errors. But thanks for the compliment and the thoughtful response.
>
> A POD-struct is an aggregate class that has no non-volatile
> data members of type pointer to member, non-POD-struct, non-
> POD-union (or array of such types) or reference, and has no
> user-defined copy assignment operator and no user-defined
> destructor.
Yes, and I wonder if we should also have said 'has at most one access
specifier that must come before any declarations of non-static data
members. I sort of wonder if there is a defect hiding in here.
>
>According to 8.5.1/1:
>
> An aggregate is an array or a class (clause 9) with no user-
> declared constructors (12.1), no private or protected non-
> static data members (clause 11), no base classes (clause 10)
> and no virtual functions (10.3).
>
>Note that this does _not_ say anything about access specifiers --
>only about the actual access itself. You're free to use the public
>access specifier as often as you wish, and the class remains POD.
Perhaps this is the place where we should have added a restriction to
access specifiers.
>
>Now, if you had something that was NOT a POD-struct, _then_ you'd
>have to look at 9.2/12, which says:
>
> ... The order of allocation of non-static data members
> separated by an access-specifier is unspecified (11.1).
And note that this says nothing about it being a non-POD
>
>However, since what you declared IS a POD-struct, the implementation
>is required to follow 9.2/17, which says:
>
> A pointer to a POD-struct object, suitably converted using
> a reinterpret_cast, points to its initial member...
And for it to be a POD it is intended that it be layout compatible with
all other PODs that have the same declaration sequence. Indeed because
of the C rules about structs that share a common initial sequence
(important for unions) I think we should have said more because the
intent of a POD is that it should be layout compatible with the
equivalent declaration applied by a compatible C compiler.
>
>As such, the compiler _must_ arrange your struct so that y is at the
>very beginning of the struct. After that must come f (possibly
>separated by some padding) and finally z. Francis's example is
>similar -- if you start with a pointer to struct Z, and
>reinterpret_cast it to int*, it _must_ point to Z::y; the compiler is
>NOT allowed to rearrange the layout to place Z::f before Z::y.
I agree, but I think we should be requiring more for a POD and so should
be more restricitve as to what a POD is.
>
>I don't think the rules on POD structs are quite strong enough to
>ensure what was really originally intended though. Given a
>declaration like:
I agree, but I think they should eliminate the following as a POD.
>
>struct A {
>public: int x;
>public: int y;
>public: int z;
>};
>
>The compiler can put the members either in of two possible orders: x-
>y-z OR x-z-y. Both of these satisfy the requirement in 9.2/17 but
>the latter uses the permission in 9.2/12 to rearrange members other
>than the first one even though it's clearly a POD-struct (to which I
>don't believe this permission was really intended to apply).
And I think that a struct (or class) with multiple declarative regions
for data members should not be classified as a POD.
Should we raise an issue (potential DR) on this.
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ ... ]
> But thanks for the compliment and the thoughtful response.
Certainly.
> > A POD-struct is an aggregate class that has no non-volatile
> > data members of type pointer to member, non-POD-struct, non-
> > POD-union (or array of such types) or reference, and has no
> > user-defined copy assignment operator and no user-defined
> > destructor.
> Yes, and I wonder if we should also have said 'has at most one access
> specifier that must come before any declarations of non-static data
> members. I sort of wonder if there is a defect hiding in here.
That depends a bit on viewpoint, I suppose. I doubt there's clear
consensus that the original intent was different from what's in the
standard so it's a really _obvious_ defect, but that doesn't mean
it's immune to improvement either.
> >Now, if you had something that was NOT a POD-struct, _then_ you'd
> >have to look at 9.2/12, which says:
> >
> > ... The order of allocation of non-static data members
> > separated by an access-specifier is unspecified (11.1).
>
> And note that this says nothing about it being a non-POD
True -- my wording was poor. I should have said that this still
applies, but (at least as I'd interpret things) the compiler is only
free to take this permission to the extent that it does NOT violate
any other part of the standard in the process.
[ ... ]
> >struct A {
> >public: int x;
> >public: int y;
> >public: int z;
> >};
[ ... ]
> And I think that a struct (or class) with multiple declarative regions
> for data members should not be classified as a POD.
I'm not sure I agree. One reason for the rules about PODs is to
allow C and C++ files that use common headers to link together and
use the same struct layouts. Clearly including ANY access specifier
renders this a moot point, since they're not legal in C declarations
(they'd be interpreted as labels, which I'm reasonably certain aren't
allowed in struct declarations).
If I'm not mistaken, you should also be able to do a bitwise copy of
one POD to a compatible POD and get defined results. Including an
access specifier doesn't automatically negate this. I can see some
arguments in both directions here. On one hand, giving an access
specifier that _looks_ vacuous a meaning that's not even remotely
related to access seems like a rather poor idea. OTOH, most of the
time the access specifier has that meaning anyway.
I'm generally in favor of giving the compiler as much latitude as
possible to help it produce better code. At the same time, I'm hard
put to come up with a good reason to believe that rearranging a few
elements in a struct is really likely to make any huge difference;
this isn't exactly a new technology area where great new technology
is happening on a regular basis.
As such, I'm not sure what's really gained by restricting PODs in
this fashion.
> Should we raise an issue (potential DR) on this.
I agree that things really aren't very good the way they are -- the
rules are confusing enough that I'm still not sure I reached the
right conclusion, even right after looking at the standard. I think
it's safe to say that six months from now I won't know them without
looking at the standard again. I also certainly can't provide any
reasonable explanation for _why_ the example I gave should really be
treated differently than the one you gave.
I'm a bit less certain about what resolution to suggest though. One
obvious possibility would be the one you gave: something is only a
POD struct if it contains at most one access specifier, which must
precede all declarations of non-static members. Another possibility
would be to amend 9.2/12 to apply only to structs of non-POD type.
Personally, I _tend_ to favor the latter, but only by a very slight
margin. Most of my reasoning is fairly simple: POD-structs tend to
matter the most to people mixing C and C++. This often happens when
people are in the process of switching from C to C++. Expecting such
a person to learn an esoteric rule about a far-from-obvious meaning
of an access specifier right away seems (at least to me) like little
more than an unnecessary road-block.
--
Later,
Jerry.
The universe is a figment of its own imagination.
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
> As such, I'm not sure what's really gained by restricting PODs in
> this fashion....POD-structs tend to
> matter the most to people mixing C and C++.
Consider 9.5 (unions).
"If a POD-union contains several POD-struts that share a common initial
sequence (9.2), and if an object of this POD-union type contains one of
the POD-structs, it is permitted to inspect the common initial sequence
of any of POD-struct members; see 9.2"
Obviously, this works only if the POD-structs do not have any access
specifier labels in the common initial sequence. This problem has
nothing to do with C compatibility.
--
Ray Lischner, author of C++ in a Nutshell (forthcoming)
http://www.tempest-sw.com/cpp/
[snipped discussion of whether or not an access specifier negates POD-ness]
> POD-structs tend to
> matter the most to people mixing C and C++.
POD-structs also have magical properties, like the ability to be statically
initialized, memcpy'd around, or even left uninitialized, which make them
useful for people dealing exlusively with C++, too.
Anthony
--
Anthony Williams
Senior Software Engineer, Beran Instruments Ltd.
Remove NOSPAM when replying, for timely response.
I think it very unlikely that a newcomer to C++ would think about using
multiple access specifiers for data, particularly as all data must be
public in a POD so the problem only occurs if the programmer uses
multiple 'public' access qualifiers.
What we have at the moment is that multiple public access specifiers do
allow some re-ordering even in a POD type, and that contravenes the
intent (to define types that are layout compatible with C types)
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
Except that the entire issue of PODs is to do with C Compatibility and
in particular the license to inspect the shared initial sequence.
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
> In message <57cb.3ddb...@prospero.island.local>, Ray Lischner
>>Obviously, this works only if the POD-structs do not have any access
>>specifier labels in the common initial sequence. This problem has
>>nothing to do with C compatibility.
>
> Except that the entire issue of PODs is to do with C Compatibility and
> in particular the license to inspect the shared initial sequence.
Pardon me for being dense, but I don't understand your point. I agree
that the main issue of PODs is C compatibility, but my argument is that
the issue is somewhat broader than that, and I cited an example where
the problem of access specifier labels and PODs has an impact without
bringing C compatibility into the picture.
I brought this up over a month ago, but the discussion fizzled. I agree
with you that there should be a DR on this. I haven't had the time to
formulate a coherent report yet.
--
Ray Lischner, author of C++ in a Nutshell (forthcoming)
http://www.tempest-sw.com/cpp/
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ ... ]
> Consider 9.5 (unions).
>
> "If a POD-union contains several POD-struts that share a common initial
> sequence (9.2), and if an object of this POD-union type contains one of
> the POD-structs, it is permitted to inspect the common initial sequence
> of any of POD-struct members; see 9.2"
>
> Obviously, this works only if the POD-structs do not have any access
> specifier labels in the common initial sequence. This problem has
> nothing to do with C compatibility.
I'm forced to disagree: if C compatibility wasn't a concern, I doubt
that there would be such a thing as a union to start with. Instead,
you'd simply use inheritance, and the common initial sequence would
be the members of the base class.
I'm not sure there's any restrict on there being on access specifiers
in the common initial sequence (I can't find any) so this may be
enough to prevent the compiler from rearranging members of a POD,
even though 9.2/12 says it should be able to -- at least most of the
time, the compiler can't tell when/if you might create a union that
includes this struct, and any or all members of the struct might be
part of a common initial sequence with some other struct that didn't
include any access specifiers, so they have to be arranged in the
same order, and they weren't allowed to be rearranged in the other
struct, so they can't in one with access specifiers either.
Given the convoluted path it takes to get to this conclusion,
however, I'm more convinced than ever that this really needs to be
written up for a DR, but I'm less certain than ever of what to
propose as a solution.
--
Later,
Jerry.
The universe is a figment of its own imagination.
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
>> >specifier labels in the common initial sequence. This problem has
>> >nothing to do with C compatibility.
> >
> > Except that the entire issue of PODs is to do with C Compatibility
> > and in particular the license to inspect the shared initial
> > sequence.
>
>Pardon me for being dense, but I don't understand your point. I agree
>that the main issue of PODs is C compatibility, but my argument is that
>the issue is somewhat broader than that, and I cited an example where
>the problem of access specifier labels and PODs has an impact without
>bringing C compatibility into the picture.
I think the confusion is that you are looking at the issues that arise
today within C++ even without linking code to C code, or requiring that
the code can be compiled as C as well as C++ (but then access specifiers
go out the window) I am looking at why these issues arise in C++ at all.
Had we not had to design for C compatibility I doubt that we would have
concerned our selves with such things as common start sequences shared
by members of a union.
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
I'm going to ask another question, then, that concerns another common
method of C/C++ POD compatibility: subclassing. What about this:
struct A {
int x;
float y;
};
struct B : public A {
private:
double z;
};
What are the rules governing whether a B can successfully be converted
to an A when passing it to an extern "C" function? I would assume that
casting likely won't rearrange member order. Is the inheriting from a
POD type enough to gurantee that the order of data inherited from the
POD class is guranteed?
Sean
Well that is a POD so we have some guarantees about layout.
>
>struct B : public A {
>private:
> double z;
>};
>
>What are the rules governing whether a B can successfully be converted
>to an A when passing it to an extern "C" function?
The only way you could pass it to a C function would be by value. That
means that the A part of a B object will be copied (and so sliced). The
result will be that you have an ordinary A object.
Well it isn't quite the only way because you could use an A* and that
answers your underlying question. As there are no virtual functions
lying around (and so supporting typeinfo) the compiler must be able to
get the right behaviour from an A* without knowing if it points to an A
object or to one derived from an A object.
> I would assume that
>casting likely won't rearrange member order. Is the inheriting from a
>POD type enough to gurantee that the order of data inherited from the
>POD class is guranteed?
--
Francis Glassborow ACCU
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]