Re: [Solved] sequence of inheritance from virtual base class?
On Mon, 20 May 2013 12:51:34 -0700, Francis Glassborow wrote:
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.
It was only a problem because the source pointer did, in fact, *not*
refer to a Base (sub-)object.
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
As bar() takes its argument as a pointer, there is no risk at all of
slicing. The only possible "problem" is that, if Base does not have any
virtual functions, then bar() can't take any advantage of what Derived
has to offer.
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* ?
No, there are no problems of any kind in the code you presented.
The implicit conversion from Derived (reference or pointer) to Base
(reference or pointer) and a static_cast in either direction must take
the offset of the Base sub-object within Derived into account.
This requirement does not hold for reinterpret_cast, or if the conversion
goes through an intermediary type (such as void*).
It was this latter aspect of which the code from the OP ran afoul. It
converted a Derived* to a Base* through a void* in one way, and directly
in the reverse way. This created havoc with a nonzero offset of the Base
sub-object.
I suspect that we (maybe just me) have got confused. I know that we
cannot cast back from Base* to Derived*.
Actually, if you know that the pointer refers to a Base sub-object, then
a static_cast to Derived (pointer or reference) is completely well-
defined (unless they removed that from C++11, which I doubt).
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<>.
It is not as black-and-white as you paint it here, but dynamic_cast<>
*does* give you more guarantees if you made an error in remembering which
most-derived class your pointer actually refers to.
You *can* make the conversion with static_cast<>, but you are on your own
if you screw up (as in, UB).
Bart v Ingen Schenau
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]