Re: Is the aliasing rule symmetric?
On Feb 6, 7:55 am, "Johannes Schaub (litb)"
<schaub.johan...@googlemail.com> wrote:
Johannes Schaub (litb) wrote:
Joshua Maurice wrote:
On Jan 21, 9:20 am, "Johannes Schaub (litb)" <schaub-johan...@web.de>
wrote:
Ben Bacarisse wrote:
"Johannes Schaub (litb)" <schaub-johan...@web.de> writes:
Would we be allowed to do this in the opposite direction, if we kn=
ow
that the alignment is fine?
What's the opposite direction? Are you asking if changing the=
int
will
change the value of *b? If so, yes (provided the new int valu=
e's bits
do indeed affect the byte in question).
I mean to ask: If aliasing of an A object by an lvalue of type B is O=
K,
is aliasing of a B object by an lvalue of type A OK?
No. Don't think about it as an aliasing rule. Think about it as a rule
which restricts the types of lvalues with which you can legally access
objects.
You can always access an object through a char or unsigned char
lvalue. (Or maybe it's only for POD types - there's no consensus. I
would only use char and unsigned char to access POD objects.)
You can always access an object through a base class lvalue, but you
can never do the reverse: you can never take a complete object of type
T and access it through a derived type of type T.
You cannot access an object of derived class type and access it as a ba=
se
class lvalue either. You always need to point to the proper base class
subobject. If you try to directly access the complete object by a base
class lvalue, you will be lucky if it crashes.
In this sense it's the same for base/derived relationship in both
directions. If the base-class subobject and the complete object have th=
e
same address, you can reinterpret_cast and if you aren't lucky you can
read/write with the resulting lvalue. If you do the proper thing and us=
e
an implicit conversion or an explicit conversion (for the downcast), yo=
u
have defined behavior. But that has nothing to do with the aliasing rul=
e.
IMO the respective bullet in 3.10p15 is flawed.
Having thought about this again, I think the respective bullet is NOT
flawed. The bullet implies that you already have made a successful
conversion and have a proper lvalue.
We do actually have the reverse (access a base class object by the derive=
d
class type), by means of "the dynamic type of the object" (first bullet).=
It
is catched by that, and to my surprise, if you turn around the bullet abo=
ut
the base-class subobject rule according to symmetry rule, you get nearly =
the
same wording
- a type that is the (possibly cv-quali=EF=AC=81ed) dynamic class =
type of
the type of the object
Implicit in that entire piece of standard is that you obtained that
lvalue through a "proper" explicit or implicit conversion or cast. If
you start throwing around reinterpret_casts, then it's quite easy to
break it. Consider:
struct A { int x; };
struct B : A {};
int main()
{
B b;
b.x = 1;
A* a = & b;
return a->x;
}
Now, what's left is quite pedantic, and I'm not sure of the exact
nomenclature. When I access the base class subobject ala "return a-
x;", is that consider "accessing the stored value of the [derived
class] object" according to the wording of C++03 "3.10 Lvalues and
rvalues / 15" ? I presume yes. Those bullets are there just as
allowance that you /can/ access base class subobjects through base
class type lvalues and through lvalues of the member types, and you
can access the object through the dynamic type of the object. It
doesn't mention that the lvalues must have been properly obtained -
the following is an example of improperly obtaining the lvalue:
int main()
{
B b;
b.x = 1;
A* a = reinterpret_cast<A*>(&b);
return a->x;
}
Is the above UB? I don't know. Maybe? Either way you should never do
it. It definitely is UB if we have virtual or multiple inheritance.
Where is this fundamental distinction mentioned in the standard?
Nowhere where I can see.
So I think we again see that the following rule seems to be true:
If aliasing of an A object by an lvalue of type B is OK,
is aliasing of a B object by an lvalue of type A OK?
Please correct me If I'm misunderstanding anything.
Well, yes. If you have an A object, and you can access a sub-object of
that, or a containing object of that, through a B lvalue, then you can
definitely take that same B object, and access the corresponding A
object through an A lvalue. Are you trying to say something more?