Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Safely casting pointer types, purpose of static_cast, etc.

Reply
Thread Tools

Safely casting pointer types, purpose of static_cast, etc.

 
 
jason.cipriani@gmail.com
Guest
Posts: n/a
 
      06-04-2008
There have been some recent threads about casting pointers to and from
void* that have me rethinking some of my usual practices. I have a
couple of questions.

1. What is the purpose of C++'s static_cast<>? In other words, is
there any real difference between statements like (with non-pointer
types):

double a = 3.4;
int b = (int)a; // <--- this
int c = static_cast<int>(a); // <---

2. What about static cast with void*'s and pointers to class types, is
there any difference here, and also, are these conversions all safe:

Object *a = new Object;
void *b = a;
Object *c = (Object *)b;
Object *d = static_cast<Object *>(b);

In that code is there any difference between the conversion when
initializing c and d? And, are c/d guaranteed to be valid pointers to
the same object a points to?

3. If c/d are not guaranteed to be valid pointers, 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 ===

Thanks,

Jason
 
Reply With Quote
 
 
 
 
Jayesh Shah
Guest
Posts: n/a
 
      06-05-2008
There is not much difference but static casting is more
restrictive(safer) and noticeable.

On Jun 4, 4:21 pm, "jason.cipri...@gmail.com"
<jason.cipri...@gmail.com> wrote:
> There have been some recent threads about casting pointers to and from
> void* that have me rethinking some of my usual practices. I have a
> couple of questions.
>
> 1. What is the purpose of C++'s static_cast<>? In other words, is
> there any real difference between statements like (with non-pointer
> types):
>
> double a = 3.4;
> int b = (int)a; // <--- this
> int c = static_cast<int>(a); // <---
>
> 2. What about static cast with void*'s and pointers to class types, is
> there any difference here, and also, are these conversions all safe:
>
> Object *a = new Object;
> void *b = a;
> Object *c = (Object *)b;
> Object *d = static_cast<Object *>(b);
>
> In that code is there any difference between the conversion when
> initializing c and d? And, are c/d guaranteed to be valid pointers to
> the same object a points to?
>
> 3. If c/d are not guaranteed to be valid pointers, 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 ===
>
> Thanks,
>
> Jason


 
Reply With Quote
 
 
 
 
Jerry Coffin
Guest
Posts: n/a
 
      06-05-2008
In article <d5ce22d0-225b-42e4-8d6c-
>,
says...

[ ... ]

> 1. What is the purpose of C++'s static_cast<>? In other words, is
> there any real difference between statements like (with non-pointer
> types):
>
> double a = 3.4;
> int b = (int)a; // <--- this
> int c = static_cast<int>(a); // <---


There is no difference between these statements. For that matter,

int c = 3.4;

is allowed, and does exactly the same thing as well.

The reason for static_cast over a C-style cast is mostly that it is more
restricted, and does NOT support some more dangerous conversions that C-
style casts can do. For example, a C-style cast can do roughly the same
thing as a const_cast, casting away const-ness, or it can do roughly the
same thing as a reinterpret_cast, treating a pointer as if it pointed to
a different type of operand.

> 2. What about static cast with void*'s and pointers to class types, is
> there any difference here, and also, are these conversions all safe:
>
> Object *a = new Object;
> void *b = a;
> Object *c = (Object *)b;
> Object *d = static_cast<Object *>(b);
>
> In that code is there any difference between the conversion when
> initializing c and d? And, are c/d guaranteed to be valid pointers to
> the same object a points to?


Yes, the conversions to c and d are the same. A C-style cast does the
same thing as a static_cast when/if a static_cast can do the conversion.
A static_cast can't do anything new that a C-style cast can't. The
advantage of a static_cast is solely that it is more restricted, so you
can't, for one example, accidentally cast away const-ness and/or
reinterpret what a pointer points at -- for example:

int const *a;
char *b = (char *)a; // perfectly legal
char *b = static_cast<char *>(a); // not allowed

The C-style cast is casting away the const-ness AND reintrepting what's
pointed at as a char instead of an int. A static_cast simply can't do
that -- if you really want to cast away const-ness, you need to use
const_cast. If you want to reinterpret what's pointed at, you have to
use reinterpret_cast. If you want to do both, you have to use both:

char *c = const_cast<char *>(reinterpret_cast<char const *>(a));

The C-style cast can do so many different kinds of conversions, with
nothing to distinguish between them, that it's easy to accidentally do a
conversion you don't want along with the one(s) you did. The new-style
casts attempt to prevent that.

--
Later,
Jerry.

The universe is a figment of its own imagination.
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      06-05-2008
On Jun 5, 1:21 am, "jason.cipri...@gmail.com"
<jason.cipri...@gmail.com> wrote:
> There have been some recent threads about casting pointers to
> and from void* that have me rethinking some of my usual
> practices. I have a couple of questions.


> 1. What is the purpose of C++'s static_cast<>?


To limit the types of casts which can be done. You can't
accidentally cast away const with it, for example. More
importantly, in a class hierarchy, a C style cast is a
static_cast if it is to a base or a derived, but a
reinterpret_cast (i.e. type punning) if it is to a sibling. (An
attempt to use static_cast in this case will cause compiler
error.) Also, static_cast (and dynamic_cast) respect the access
specifiers in an inheritance hierarchy; C style casts don't.

> In other words, is there any real difference between
> statements like (with non-pointer types):


Unless the types are pointers or references in an inheritance
hierarchy, there is not difference between a C style cast and a
static_cast, *if* the static_cast is legal. For non-pointer and
non-reference types, in fact, most code I've seen doesn't use
static_cast, but rather the function style casts, e.g.:
"MyClass( 43 )".

> double a = 3.4;
> int b = (int)a; // <--- this
> int c = static_cast<int>(a); // <---


These two are totally indentical. Conceptually, I tend to think
of this as creating a new temporary object, rather than
accessing an existing object through a different type. In such
cases, I'll use a function style cast, or a C style cast with
the argument in parentheses, i.e. "int( a )" or "(int)( a )".
(The latter is necessary if the typename is not a single token,
e.g. "unsigned char".) In my mind, this is the syntax for
"creating a new, temporary object".

(Technically, a pointer cast also creates a new, temporary
object. But the new object is a pointer, and of course, for the
most part, when you use a pointer cast, you're concerned about
the access through the pointer.)

> 2. What about static cast with void*'s and pointers to class
> types, is there any difference here, and also, are these
> conversions all safe:


> Object *a = new Object;
> void *b = a;
> Object *c = (Object *)b;
> Object *d = static_cast<Object *>(b);


> In that code is there any difference between the conversion
> when initializing c and d? And, are c/d guaranteed to be valid
> pointers to the same object a points to?


No difference, and yes. You can convert any pointer type to
void*, and convert it back *to* *the* *same* *type* without loss
of information. (Note that this more or less implies that void
pointers will be at least as large as any other pointer type.)

> 3. If c/d are not guaranteed to be valid pointers,


Irrelevant, because they are. I'd use static_cast in this case.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      06-05-2008
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:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
jason.cipriani@gmail.com
Guest
Posts: n/a
 
      06-08-2008
Sorry, there's too much to quote, but thanks Jayesh, Jerry, James, for
the complete answers, and for keeping the non-J riff raff out as well.

- Jason
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Casting from pointer types to non-pointer types jois.de.vivre@gmail.com C++ 11 06-07-2007 09:17 AM
Safely deleting a type-casted pointer Pat C++ 1 02-22-2007 07:33 PM
Casting a file pointer to char pointer Abhishek C Programming 9 03-22-2006 07:48 AM
Another question about inheritance (up-casting and down-casting) kevin Java 11 01-08-2005 07:11 PM
ISO C++ forbids casting between pointer-to-function and pointer-to-object ken C++ 3 11-08-2003 12:08 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57