Topic: Where does this break?
Author: klamer@mi.el.utwente.nl (Klamer Schutte)
Date: Mon, 1 Mar 1993 10:25:25 GMT Raw View
Hi,
I consider using a piece of code which basically does this:
class A
{
public:
// Simple data (integers) and members.
// This is automatically generated code, and i don't want to change it.
// No constructor / desctructor
void init_me(void **ptr)
{ *ptr = this; }
};
class B : public A
{
C object; // C fancy class designed by myself
public:
B(void **ptr)
{ init_me( ptr ); }
// some members
};
void *the_ptr;
...
B *b = new B( &the_ptr ); // So basically, the_ptr = (A *)&b;
...
B *b_ptr = (B *) the_ptr; // So b_ptr = (B *)(void *)(A *)&b;
And the rest of the code assumes that b_ptr == b. I am using g++ 2.3.3 now,
and this seems to work. I also know that it is not allowed according to ARM.
And since fixing the (automatic generated) code is a lot of work, i have the
next question:
Does anybody know of an exsisting C++ compiler where the above construct does
not work? Does anybody think future compilers will not work with the above
code?
And the other question is:
What changes in the above code do break it, on compilers which currently
work with the above code? (Yes, i have thought of changing A into
a virtual base class of B. So i don't :-)
Perhaps it also might be interesting to know:
1) whether a lot of people use kludges as above
2) whether people really think that code such as above should be avoided on
all occasions.
I will summarize responses i get by e-mail.
Klamer
--
Klamer Schutte Tel: +31-53-892778 Fax: +31-53-340045
Faculty of electrical engineering -- University of Twente, The Netherlands
preferred: klamer@mi.el.utwente.nl SMTP: klamer@utelmi01.el.utwente.nl
Author: steve@taumet.com (Steve Clamage)
Date: Wed, 3 Mar 1993 17:21:05 GMT Raw View
klamer@mi.el.utwente.nl (Klamer Schutte) writes:
>class A
>{
>public:
> void init_me(void **ptr) { *ptr = this; }
>};
>class B : public A
>{
>public:
> B(void **ptr) { init_me( ptr ); }
>};
>void *the_ptr;
>B *b = new B( &the_ptr ); // So basically, the_ptr = (A *)&b;
>B *b_ptr = (B *) the_ptr; // So b_ptr = (B *)(void *)(A *)&b;
No, this does not in general work as you want. When it does, it is
only by accident.
Conversion of pointers within a class hierarchy in general requires
execution of code. The compiler must rely on the static (declared)
types of objects to perform casts. Once you cast to a void*, you
throw away all the type information. Any needed adjustments can no
longer occur. In the last line, any adjustment required to go from
A* to B* would not occur.
Most (all?) compilers lay out classes so that a derived class with
one immediate non-virtual base class begins at the same address as
the base class, and no pointer conversion is needed. This layout
is not a language requirement, so you should not depend on it.
Even if the layout were required, the practice is a bug waiting
to happen. Seemingly innocent changes to the hierarchy could
result in program failure with no warning from the compiler.
--
Steve Clamage, TauMetric Corp, steve@taumet.com