Re: casting (void *) to (class *)
On Apr 15, 4:04 am, "Alf P. Steinbach" <al...@start.no> wrote:
* Jonathan Lee:
But better, don't use void* pointers (except for the special
case of identifying objects in e.g. a hash table, in which
case you should make sure to have pointers to complete
objects, e.g. obtained by dynamic_cast to void*).
I'm not sure I understand this one. Do you mean just using the
pointer as the key? (And how do you get a hash value for a
pointer, portably?)
However, void* may be practically necessary in the context of
a C code callback.
Yes, and you can encounter a similar problem to the above.
About the only legal thing you can do with a void* is cast it
back to the original type (and only that type) before using it.
(You can, of course, copy it and compare it.) Thus, the
following is undefined behavior:
Derived* p1 = new Derived ;
void* p2 = p1 ;
Base* p3 = static_cast< Base* >( p2 ) ;
p3 -> ...
The second line must be written:
void* p2 = static_cast< Base* >( p1 ) ;
for the rest to work.
(This often happens in callback contexts, e.g. pthread_create or
CreateThread, where the called function does something like:
void*
newThread( void* p )
{
static_cast< Base* >( p )->run() ;
}
Passing the address of this function and a pointer to a derived
type to pthread_create or CreateThread will cause undefined
behavior.)
For context, it's for a "thread" class with pthreads backing
it. I know that the void* was originally a pointer to the
class and it is merely being restored to the correct type
(it's just the _this_ pointer being mangled by
pthread_create).
There is a good chance that the original pointer was just
implicitly converted to void*, in which case the conversion
was equivalent to a static_cast, which is then what you should
do to get back the original.
But consider using Boost threads.
AFAIK they're based on pthreads, but offering a more type safe
C++ interface, and in addition, will be part of C++0x so using
them is preparing for the future...
Actually, this is one place where the standard did evolve
significantly from Boost: the thread and its identifier have
been separated, there is an explicit function for detach
(although the implicit detach in the constructor is still
there, rather than having it an error condition to destruct a
joinable thread), and of course, the standard type makes use of
new standard features, like rvalue references and move
semantics.
Of course, it still fails to make detached and joinable threads
two distinct types---in fact, there's no need for a "type" for
detached threads, just a function to start them, and you
typically don't want copy or move semantics for the constructor
arguments for a joinable thread. Using the same basic interface
for both means we have a compromize. Depending on the use, the
use of copy semantics may make starting a joinable thread much
more expensive than necessary---this is certainly the case for
Boost, at any rate. I'm not sure how move semantics interact
with threads, so I can't say too much about the impact there.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34