Re: [Solved] sequence of inheritance from virtual base class?
On 20/05/2013 13:40, Daniel Kr?gler wrote:
Am 20.05.2013 12:16, schrieb Francis Glassborow:
On 20/05/2013 00:39, Wil Evers wrote:
I think the lesson to learn from this thread is that a void pointer
obtained from the address of an X must not be cast back to a
pointer to some other type, even if that other type is closely
related to X.
static_cast<Base> should convert the pointer if necessary,
reinterpret_cast<Base> can fail.
I don't think that static_cast versus reinterpret_cast is relevant in
the here discussed conversion case. The reason for the observed
problem really is (as others have said in different words) that the
language doesn't specify that the conversion sequence (all by means of
static_cast)
D* d1 -> void* v -> B* b -> D* d2
where B* and D* do have an effective offset different from zero, will
return an address value d2 that is equal to the original address value
d1. The constraint is expressed in 5.2.9 p13:
"A prvalue of type ?pointer to cv1 void? can be converted to a prvalue
of type ?pointer to cv2 T,? [..] If the original pointer value
represents the address A of a byte in memory and A satisfies the
alignment requirement of T, then the resulting pointer value
represents the same address as the original pointer value, that is,
A. The result of any other such pointer conversion is unspecified. A
value of type pointer to object converted to ?pointer to cv void? and
back, possibly with different cv-qualification, shall have its
original value."
The behavior of above sequence is undefined, because the assumption
that b points to the same address value as the original address value
of d1 is invalid.
Agreed but it is the step from Base* to Derived* that is the problem. I
was merely addressing the Derived* to Base* conversion which AFAIK was
and remains valid if done via a static_cast<>
Consider:
class Base {
// whatever
};
class Derived: public Base (
//whatever
};
void bar(Base *);
void foo(){
Base * b1_ptr = new Derived;
Base * b2_ptr = new Base;
bar(b1_ptr); // possible problem with slicing
bar(b2_ptr); // no problems
}
Do we now have a problem not just with slicing, but fundamentally that
this what is passed to bar may not even be a Base* ?
I suspect that we (maybe just me) have got confused. I know that we
cannot cast back from Base* to Derived*. However if we use a
static_cast<> we will obtain the address of the Base part of Derived
even if that is different to the address of the derived object.
The ability to go there and back is limited to polymorphic types and
using dynamic_cast<>. If the implementation were required to place the
Base object at the address of the derived then reinterpret_cast<> would
work. But that has never been the case. (I can remember bringing an
otherwise excellent author to task for that misunderstanding back in the
90s)
Anyway the main point is that other from the extended (by C++11) concept
of Plain Old Data types we have few guarantees about layout though C++11
does require that data with the same access specifier shall be placed in
order though possibly interleaved with data with a different access
specifier (and presumably that interleaving continues to be available
for base class data in a derived class:
struct Base {
int i;
char c;
double d;
};
struct Derived public Base {
int j;
char c1;
double d1;
};
?? Derived can be laid out as:
j, i, c, c1, d, d1
??
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]