Re: Safely casting pointer types, purpose of static_cast, etc.
On Jun 5, 1:21 am, "jason.cipri...@gmail.com"
<jason.cipri...@gmail.com> wrote:
[...]
3. If c/d are not guaranteed to be valid pointers,
As I said, they are guaranteed to be valid, but I missed some
important issues in your example.
what is the correct way to do that conversion in a situation
where a void* must be used as an intermediate variable to hold
a pointer to an object (e.g. when passing through a layer of C
code)? For example, when creating a thread with
pthread_create, a void* parameter can be passed to the thread
function. So, then, is the following code guaranteed to always
do what I want on any platform:
=== BEGIN EXAMPLE ===
class A {
public:
void CreateThread ();
private:
void * MyThreadProc_ ();
static void * SThreadProc_ (void *);
};
// creates a thread
void A::CreateThread () {
pthread_t tid;
// 4th param is void* param to pass to SThreadProc_.
pthread_create(&tid, NULL, &SThreadProc_, this);
}
// static thread function calls ((A*)va)->MyThreadProc_();
void * A::SThreadProc_ (void *va) {
A *a = (A *)va; // <--- is this always safe?
return a->MyThreadProc_();
}
=== END EXAMPLE ===
First, this won't compile with a compliant compiler. The type
of the third parameter to pthread_create is ``extern "C" void*
(*) (void*)'', and a member function, even static, can never
have a type with ``extern "C"''. You *must* use a free function
for this.
Secondly, as I said in my previous answer, the type you get from
the void* *must* be the same type as you used to create it.
That's not a problem here, but it very much could be if you
derive. A common mistaken idiom is something like:
class ThreadBase
{
public:
virtual ~ThreadBase() {}
virtual void run() = 0 ;
} ;
extern "C" void*
threadStarter( void* p )
{
static_cast< ThreadBase* >( p )->run() ;
return NULL ;
}
class MyThread : public ThreadBase
{
public:
virtual void run() ;
// ...
} ;
and then somewhere:
MyThread t ;
pthread_t ti ;
pthread_create( &ti, NULL, &threadStarter, &t ) ;
This does *not* work. Or rather, it is undefined behavior,
which may seem to work in some frequent cases. The last line
must be:
pthread_create( &ti, NULL, &threadStarter,
static_cast< ThreadBase* >( &t ) ) ;
for the behavior to be guaranteed---the cast from void* is to
ThreadBase*, so the void* must have been created from a
ThreadBase*, and not a MyThread*.
--
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