stroustrup, void*, and reinterpret_cast

568 views
Skip to first unread message

andre...@yahoo.com

unread,
Aug 30, 2006, 11:02:30 AM8/30/06
to
Hi,

I've noticed that on pg. 342 of Stroustups "C++ Programming Language"
book his example of using partial specialization for a custom vector
template where T is a pointer to anything to avoid bloat, he uses
reinterpret_cast to go back and forth between void* and T* pointers.
Why? Why not use static_cast?

1) he made a mistake (unlikely)
2) does static_cast with complicated T* to void* cause address shifts?
If so this could cause problems with preservation of a NULL value as
well as a round-trip inconsistency. My feeling is that
reinterpret_cast simply will not change the actual pointer value stored
from the assembly perspective in either direction, which is desired.
3) is it because of ever so slightly better performance?

As a result of his example, I have decided throughout my program to use
reinterpret_cast to go back and forth between void* and typed pointers.
I use static_cast only when narrowing to a derived type from a base
class type.

Can anyone give me the decisive opinion on this issue with
reinterpret_cast and void*, and in particular, why Stroustup uses
reinterpret_cast instead of static_cast?

Thanks,
Andy


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Frederick Gotham

unread,
Aug 31, 2006, 11:02:27 AM8/31/06
to
andre...@yahoo.com posted:

> As a result of his example, I have decided throughout my program to use
> reinterpret_cast to go back and forth between void* and typed pointers.


Why adopt someone else's style before you even understand why? It is not a
good way to learn.

If you want to convert a void* to any other pointer type, use static_cast:

void *pv = 0;
int *pi = static_cast<int*>(pv);

I don't have Bjarne's book here with me, so I can't look over the code
snippet. Perhaps he used reinterpret_cast simply because it slipped his mind

that static_cast would get the job done.

--

Frederick Gotham

Josef Svitak

unread,
Aug 31, 2006, 3:18:57 PM8/31/06
to
andre...@yahoo.com wrote:
> I've noticed that on pg. 342 of Stroustups "C++ Programming Language"
> book his example of using partial specialization for a custom vector
> template where T is a pointer to anything to avoid bloat, he uses
> reinterpret_cast to go back and forth between void* and T* pointers.
> Why? Why not use static_cast?

This has been fixed in the "Special Edition" to use static_cast.

And I'd have to agree with Mr. Gotham that you should probably verify
_before_ making blanket code changes ;)

josef

andre...@yahoo.com

unread,
Aug 31, 2006, 3:10:56 PM8/31/06
to

Frederick Gotham wrote:
> I don't have Bjarne's book here with me, so I can't look over the code
> snippet. Perhaps he used reinterpret_cast simply because it slipped his
mind
>
> that static_cast would get the job done.
>

In the following code, is null preserved?

main () {
void* pv = 0;
if (static_cast<int*>(pv) == 0)
cout << "null preserved";

andre...@yahoo.com

unread,
Aug 31, 2006, 3:19:31 PM8/31/06
to

Frederick Gotham wrote:
> I don't have Bjarne's book here with me, so I can't look over the code
> snippet. Perhaps he used reinterpret_cast simply because it slipped his
mind
>
> that static_cast would get the job done.
>

It can get pretty complex for me, namely I also want to store 2 types
of pointers in a virtual hierarchy as void* and then retrieve it and
narrow it to the base class pointer. The question in the following
hierarchy of widening to an interface from 2 different derivations, and
then further widening to void*, and then being able to narrow back from
void* to the interface, what's better than my use of
reinterpret_cast<>.


class Arc;

struct ArcLink {
virtual Arc* ThisArc () = 0;
virtual ArcLink* NextLink () = 0;
};

class Arc : public ArcLink {
... some data members

public:
virtual Arc* ThisArc () { return this; }
virtual ArcLink* NextLink() { return 0; }

... additional functionality
};

class ArcLinkImpl : public ArcLink {

Arc* arc;
ArcLink* tail;

public:
virtual Arc* ThisArc () { return arc; }
virtual ArcLink* NextLink () { return tail; }
};

// from utilities for a red-black set
struct IntSetElem {

void* obj;

private:

IntSetElem* left;
IntSetElem* right;
int key;
bool color;
};

// and the question is, what casts to and from elem->obj
main () {
IntSetElem* elem1 = ...; // get an element from a set
IntSetElem* elem2 = ...; // get another
Arc* arc = ...; // create an arc
ArcLinkImpl* arclink = ...; // create an arclink

ArcLink* intf = arc; // widen
elem1->obj = reinterpret_cast<void*>(intf);
//??? can I pass arc directly to the cast here

intf = arclink; // a different widen
elem2->obj = reinterpret_cast<void*>(intf);
//??? can I pass arclink directly to the cast here

// now fetch Arc* as ArcLink*
intf = reinterpret_cast<ArcLink*>(elem1->obj);
// I bet this is ok because I made sure to stuff it
// as an ArcLink* interface pointer
// what's better???

// now fetch ArcLinkImpl* as ArcLink*
intf = reinterpret_cast<ArcLink*>(elem2->obj);
// again ok because I stuffed the ArcLinkImpl*
// as an ArcLink*
// what's better???
}

Andy

Seungbeom Kim

unread,
Aug 31, 2006, 3:20:58 PM8/31/06
to
Frederick Gotham wrote:
> andre...@yahoo.com posted:
>> As a result of his example, I have decided throughout my program to use
>> reinterpret_cast to go back and forth between void* and typed pointers.
>
> Why adopt someone else's style before you even understand why? It is not a

> good way to learn.

Because it's from a textbook, a very renowned one.
Looking back on my early days, I realise that reading others' codes
(including the style) and imitating them have been quite an effective way
to learn programming, even when I could not understand all of them.

Hence the importance of good-style examples in textbooks, and it comes to
me as a surprise that Stroustrup used reinterpret_cast where he didn't
have to, while explaining in another part of the same book that the new-
style casts were named so ugly that it could discourage their use.

--
Seungbeom Kim

Erik Max Francis

unread,
Aug 31, 2006, 8:44:56 PM8/31/06
to
andre...@yahoo.com wrote:

> As a result of his example, I have decided throughout my program to use
> reinterpret_cast to go back and forth between void* and typed pointers.
> I use static_cast only when narrowing to a derived type from a base
> class type.
>
> Can anyone give me the decisive opinion on this issue with
> reinterpret_cast and void*, and in particular, why Stroustup uses
> reinterpret_cast instead of static_cast?

It's a typo. It's corrected in later editions; the snippet of code on
p. 342 of my third edition doesn't contain any reinterpret_casts.

In other words, it's a pretty good idea to make sure you understand
_why_ something is done before you start doing it yourself. Even
respected texts contain errors, and furthermore, even experts sometimes
get things wrong.

--
Erik Max Francis && m...@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 20 N 121 53 W && AIM erikmaxfrancis
Would a harvest from my heart / Find its season
-- Sandra St. Victor

Greg Herlihy

unread,
Sep 1, 2006, 8:46:02 AM9/1/06
to
andre...@yahoo.com wrote:
> Hi,
>
> I've noticed that on pg. 342 of Stroustups "C++ Programming Language"
> book his example of using partial specialization for a custom vector
> template where T is a pointer to anything to avoid bloat, he uses
> reinterpret_cast to go back and forth between void* and T* pointers.
> Why? Why not use static_cast?
>
> 1) he made a mistake (unlikely)

A mistake is indeed unlikely. So logically, we can speculate that using
reinterpret_cast at the time this example was written - was likely not
a mistake in C++.

> 2) does static_cast with complicated T* to void* cause address shifts?
> If so this could cause problems with preservation of a NULL value as
> well as a round-trip inconsistency. My feeling is that
> reinterpret_cast simply will not change the actual pointer value stored
> from the assembly perspective in either direction, which is desired.

If changing the actual pointer value is undesirable - why would a
static_cast change the pointer value any more than reinterpret_cast? A
void pointer can be a pointer to any type - so with each type just as
likely as the other, would we not expect either cast to leave the
pointer's value unchanged?

> 3) is it because of ever so slightly better performance?

Not a chance.

> As a result of his example, I have decided throughout my program to use
> reinterpret_cast to go back and forth between void* and typed pointers.
> I use static_cast only when narrowing to a derived type from a base
> class type.

I'm afraid you that you fell victim to the "argument from authority"
logical fallacy (or, for those more familiar with its Latin name: the
"argumentum ad verecundiam'' or simply the "ipse dixit" line of
reasoning. Wikipedia has a good article on this all-too-common fallacy:
http://en.wikipedia.org/wiki/Appeal_to_authority .

> Can anyone give me the decisive opinion on this issue with
> reinterpret_cast and void*, and in particular, why Stroustup uses
> reinterpret_cast instead of static_cast?

I have no idea of the actual reason - nor do I think the the issue is
particularly significant. But I would guess that - at the time - the
names of the cast operators were not yet final, so a retroactive
"mistake" was always a possibillity once the cast operators were given
names. Furthermore, choosing one or the other cast won't make any
difference to how the program runs. So rather than spend too much time
agonizing over whether to use reinterpret_cast or static_cast is the
correct choice - just pick one and move on to finishing the rest of the
program. Because - while it is true that every programmer should strive
to write correct code - it also true that no program good enough to
ship has likely ever been delayed in order for its programmers to have
time to make editorial corrections and other cosmetic improvements to
its source code.

Greg

Thomas Richter

unread,
Sep 1, 2006, 8:49:11 AM9/1/06
to
andre...@yahoo.com wrote:

> In the following code, is null preserved?
>
> main () {
> void* pv = 0;
> if (static_cast<int*>(pv) == 0)
> cout << "null preserved";
> }

Yes, of course.

So long,
Thomas

kanze

unread,
Sep 1, 2006, 8:58:50 AM9/1/06
to
andre...@yahoo.com wrote:
> Frederick Gotham wrote:
> > I don't have Bjarne's book here with me, so I can't look
> > over the code snippet. Perhaps he used reinterpret_cast
> > simply because it slipped his mind that static_cast would
> > get the job done.

> In the following code, is null preserved?

> main () {
> void* pv = 0;
> if (static_cast<int*>(pv) == 0)
> cout << "null preserved";
> }

All pointer casts preserve null.

--
James Kanze GABI Software
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

Thomas Richter

unread,
Sep 1, 2006, 8:49:48 AM9/1/06
to
andre...@yahoo.com wrote:

> It can get pretty complex for me, namely I also want to store 2 types
> of pointers in a virtual hierarchy as void* and then retrieve it and
> narrow it to the base class pointer.

Possibly a not very C++ way to approach the problem. Is this time
critical? If not, you could provide a virtual "getPointer()" method
(please choose a better name) in the base class that returns the common
base of the two objects, and use covariance to specialize this method in
the derived classes. Alternatively, use a container that is templated to
the class you want to store in.

This should probably be a template where the templare parameter
describes the object pointed to. Alternatively, why not use an
already available container from the STL or Boost? Which kind of
operations do you need for IntSetElem?

> // and the question is, what casts to and from elem->obj
> main () {
> IntSetElem* elem1 = ...; // get an element from a set
> IntSetElem* elem2 = ...; // get another
> Arc* arc = ...; // create an arc
> ArcLinkImpl* arclink = ...; // create an arclink
>
> ArcLink* intf = arc; // widen
> elem1->obj = reinterpret_cast<void*>(intf);
> //??? can I pass arc directly to the cast here

No cast is needed here, though maybe you would like to use an
IntSetElem<ArcLink> here?

> intf = arclink; // a different widen

This works.

> elem2->obj = reinterpret_cast<void*>(intf);
> //??? can I pass arclink directly to the cast here

No cast required. Every pointer can be converted to a void *
without a cast.

> // now fetch Arc* as ArcLink*
> intf = reinterpret_cast<ArcLink*>(elem1->obj);

Bad idea. Either use the template idea, or use a static_cast<>.
You do not care about the "raw bit pattern" of the pointer here. What
you want to tell the compiler is to narrow the pointer to a more
specific object.

> // I bet this is ok because I made sure to stuff it
> // as an ArcLink* interface pointer
> // what's better???

To use an already available container, likely.

> // now fetch ArcLinkImpl* as ArcLink*
> intf = reinterpret_cast<ArcLink*>(elem2->obj);
> // again ok because I stuffed the ArcLinkImpl*
> // as an ArcLink*
> // what's better???

No cast at all if you can avoid it. If elem2 would be an
IntSetElem<ArcLink> and would be declared as follows:

template<class T>
struct IntSetElem {

T* obj;

private:

IntSetElem* left;
IntSetElem* right;
int key;
bool color;
};

no cast whatsoever would be required, and type-correctness would
be guaranteed by the compiler.

By the way: Why is this a struct? And are you sure the compiler
generated copy and assignment operators are what you want?

So long,
Thomas

kanze

unread,
Sep 1, 2006, 8:59:36 AM9/1/06
to
andre...@yahoo.com wrote:
> Frederick Gotham wrote:
> > I don't have Bjarne's book here with me, so I can't look
> > over the code snippet. Perhaps he used reinterpret_cast
> > simply because it slipped his mind that static_cast would
> > get the job done.

> It can get pretty complex for me, namely I also want to store
> 2 types of pointers in a virtual hierarchy as void* and then
> retrieve it and narrow it to the base class pointer.

Both static_cast to void and reinterpret_cast have the
constraint that you must cast the pointer back to the original
type if they are to work. In your case, you should explicitly
narrow the pointer before converting it to void*, then cast back
to the narrowed type.

> class Arc;

I would have thought that that was narrowing.

> elem1->obj = reinterpret_cast<void*>(intf);
> //??? can I pass arc directly to the cast here

You don't need the cast. Note, however, that to use the void*
(other than copying it), you must first convert it to an
ArcLink* (I'd use static_cast for this), or you have undefined
behavior.

> intf = arclink; // a different widen

Again, you're using widen for the operation you described as
narrowing in the text at the top. This is derived to base.

> elem2->obj = reinterpret_cast<void*>(intf);
> //??? can I pass arclink directly to the cast here

Of course. Why would it be different than the previous case.

> // now fetch Arc* as ArcLink*
> intf = reinterpret_cast<ArcLink*>(elem1->obj);
> // I bet this is ok because I made sure to stuff it
> // as an ArcLink* interface pointer
> // what's better???

I'd use static_cast.

This is fine: you stored an ArcLink*, and you cast back to the
same type.

> // now fetch ArcLinkImpl* as ArcLink*
> intf = reinterpret_cast<ArcLink*>(elem2->obj);
> // again ok because I stuffed the ArcLinkImpl*
> // as an ArcLink*
> // what's better???

As above.

> }

I'd still be very leary of this. It's all too easy to forget
the passage through ArcLink* when storing the pointer, and then
it won't work---static_cast or reinterpret_cast when extracting
the pointer. Wrap IntSetElem in a class which takes ArcLink*
pointers, so the user cannot set the pointers without converting
his pointers to ArcLink*.

--
James Kanze GABI Software
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

Frederick Gotham

unread,
Sep 1, 2006, 4:29:59 PM9/1/06
to
Greg Herlihy posted:

> A mistake is indeed unlikely. So logically, we can speculate that using
> reinterpret_cast at the time this example was written - was likely not
> a mistake in C++.


A bit extreme don't you think... ? Programmers make mistakes here and there
-- but we catch them when we read back over our code.

I _know_ that static_cast is the one for the job, so my first guess would be

that Bjarne made a mistake by using reinterpret_cast. But then again,
there's
no observable difference in the final program.

--

Frederick Gotham

James Kanze

unread,
Sep 2, 2006, 8:57:54 PM9/2/06
to
Greg Herlihy wrote:
> andre...@yahoo.com wrote:

> > I've noticed that on pg. 342 of Stroustups "C++ Programming Language"
> > book his example of using partial specialization for a custom vector
> > template where T is a pointer to anything to avoid bloat, he uses
> > reinterpret_cast to go back and forth between void* and T* pointers.
> > Why? Why not use static_cast?

> > 1) he made a mistake (unlikely)

> A mistake is indeed unlikely. So logically, we can speculate that using
> reinterpret_cast at the time this example was written - was likely not
> a mistake in C++.

It's not really a mistake today, since it has the same effect as
static_cast in this context.

Still, Stroustrup is human (and I think he'd be the last to deny
it). Typos occur, and he's not immune to them, any more than
you or I are. He corrected it in later editions; I'd consider
that a recognition on his part that there was a mistake.

> > 2) does static_cast with complicated T* to void* cause
> > address shifts? If so this could cause problems with
> > preservation of a NULL value as well as a round-trip
> > inconsistency. My feeling is that reinterpret_cast simply
> > will not change the actual pointer value stored from the
> > assembly perspective in either direction, which is desired.

> If changing the actual pointer value is undesirable - why
> would a static_cast change the pointer value any more than
> reinterpret_cast?

Because it does. Not when casting to and from a void*, but when
casting up and down in an inheritance hierarchy.

> A void pointer can be a pointer to any type - so with each
> type just as likely as the other, would we not expect either
> cast to leave the pointer's value unchanged?

Strictly speaking: the standard does not require that the
address of a non-POD object point to the first byte of that
object; an implementation could place the vptr at the address -
4, or some such. In which case, both reinterpret_cast and
static_cast will change the physical address. (Presumable, in
the case of reinterpret_cast, because of course, all that the
standard requires is that you can cast it to void* and back to
the original type.) In practice, I've never heard of such an
implementation.

[...]


> I have no idea of the actual reason - nor do I think the the
> issue is particularly significant. But I would guess that - at
> the time - the names of the cast operators were not yet final,
> so a retroactive "mistake" was always a possibillity once the
> cast operators were given names.

The names were finalized very early, if I remember correctly.
On the other hand, our instincts as to which cast is correct
didn't really develope until after that.

> Furthermore, choosing one or the other cast won't make any
> difference to how the program runs.

But it will affect how a maintenance programmer sees the code.
Which is, in many cases, just as important.

--
James Kanze (Gabi Software) email: kanze...@neuf.fr


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

Diego Martins

unread,
Sep 5, 2006, 8:23:28 AM9/5/06
to

James Kanze wrote:
> Greg Herlihy wrote:
> > andre...@yahoo.com wrote:
>
> > > I've noticed that on pg. 342 of Stroustups "C++ Programming Language"
> > > book his example of using partial specialization for a custom vector
> > > template where T is a pointer to anything to avoid bloat, he uses
> > > reinterpret_cast to go back and forth between void* and T* pointers.
> > > Why? Why not use static_cast?
>
> > > 1) he made a mistake (unlikely)
>
> > A mistake is indeed unlikely. So logically, we can speculate that using
> > reinterpret_cast at the time this example was written - was likely not
> > a mistake in C++.
>
> It's not really a mistake today, since it has the same effect as
> static_cast in this context.
>
> Still, Stroustrup is human (and I think he'd be the last to deny
> it). Typos occur, and he's not immune to them, any more than
> you or I are. He corrected it in later editions; I'd consider
> that a recognition on his part that there was a mistake.

But it is WRONG to use reinterpret_cast in this example?
In my programs, I use reinterpret_cast to cast to void * and cast back
to the original pointer type.
Are there any drawbacks using this approach? What does static_cast buy
me in this case?

Diego Martins
HP

bjarne

unread,
Sep 5, 2006, 10:25:38 AM9/5/06
to

Diego Martins wrote:
>
> But it is WRONG to use reinterpret_cast in this example?
> In my programs, I use reinterpret_cast to cast to void * and cast back
> to the original pointer type.
> Are there any drawbacks using this approach? What does static_cast buy
> me in this case?

Not wrong, just unwise. When you use reinterpret_cast you can make
mistakes that are impossible using static_cast and using static_cast,
you can make mistakes that are impossible using C-style cast. Thus, by
using the "least powerful" cast that can do the job, you minimize
errors and the likelyhood of maintenance errors. In particular,
reinterpret_cast can convert between pointers and integers - something
you wouldn't want to happen by accident.

See http://www.research.att.com/~bs/bs_faq2.html#static-cast

Also, when you use static_cast, you stay within the semantics of the
language; when you use reinterpret_cast, you play with bits (the
representation). By doing static_cast<int*>(pv) when pv is a void*, you
assume that a void* is represented in exactly the same ways as an int*.
That's by far the most common, but not guaranted.

-- Bjarne Stroustrup; http://www.research.att.com/~bs

kanze

unread,
Sep 5, 2006, 1:04:59 PM9/5/06
to

It sends the wrong message to the reader.

When I see a reinterpret_cast in code, I immediately assume that
there is something very delicate and implementation dependant
going on. When I see a static_cast, I suppose that while you
are subverting the type system somewhat, it is within more
reasonable bounds, and is portable---I don't have to pay
particular attention to it when porting to another system, for
example.

--
James Kanze GABI Software

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

Gennaro Prota

unread,
Sep 5, 2006, 4:45:18 PM9/5/06
to
On 1 Sep 2006 08:58:50 -0400, "kanze" <ka...@gabi-soft.fr> wrote:

>All pointer casts preserve null.

True for null pointer values. It's important to distinguish those ones
from "null pointer constants", though. See core issue 463 (and/or the
current working paper).

--
Gennaro Prota

Gennaro Prota

unread,
Sep 5, 2006, 4:44:43 PM9/5/06
to
On 5 Sep 2006 10:25:38 -0400, "bjarne" <bja...@gmail.com> wrote:

>When you use reinterpret_cast you can make
>mistakes that are impossible using static_cast

Ok :-)

>and using static_cast,
>you can make mistakes that are impossible using C-style cast.

This one perplexes me. Could you please elaborate?

--
Gennaro Prota

Alf P. Steinbach

unread,
Sep 5, 2006, 4:45:42 PM9/5/06
to
* bjarne:

> using static_cast,
> you can make mistakes that are impossible using C-style cast.

Is that a typo?

Otherwise, an example would be nice.

One counter-example is a C style cast that originally worked as a
const_cast but ends up being e.g. a reinterpret_cast, which is difficult
to achieve with static_cast; another counter-example is a C style cast
that unintentionally casts to an inaccessible base (breaking the
design), which again is difficult to achieve with static_cast.

Cheers,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

kanze

unread,
Sep 6, 2006, 8:22:28 AM9/6/06
to
Gennaro Prota wrote:
> On 1 Sep 2006 08:58:50 -0400, "kanze" <ka...@gabi-soft.fr> wrote:

> >All pointer casts preserve null.

> True for null pointer values. It's important to distinguish
> those ones from "null pointer constants", though. See core
> issue 463 (and/or the current working paper).

Which represents a change compared to what was originally
adopted, according to the intent indicated in the footnote.
(In this case, it seems a reasonable change, given the small
number of cases affected.)

--
James Kanze GABI Software
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

bjarne

unread,
Sep 6, 2006, 10:50:39 AM9/6/06
to

Alf P. Steinbach wrote:
> * bjarne:
>> using static_cast,
>> you can make mistakes that are impossible using C-style cast.
>
> Is that a typo?

A typo. Sorry. "Can not"

-- Bjarne Stroustrup; http://www.research.att.com/~bs

peter koch larsen

unread,
Sep 6, 2006, 1:58:49 PM9/6/06
to

bjarne wrote:
[SNIP]

> Also, when you use static_cast, you stay within the semantics of the
> language; when you use reinterpret_cast, you play with bits (the
> representation). By doing static_cast<int*>(pv) when pv is a void*, you
> assume that a void* is represented in exactly the same ways as an int*.
> That's by far the most common, but not guaranted.

This statement scares me somewhat, but hopefully its just my
understanding of english that suffers. static_casting from e.g. void*
to int* can only be performed when the representation for void* is the
same as for int* - and there is nothing that guarantees that this will
work? So - by inference - malloc is not guaranteed to work?
I surely must misunderstand something - and yet I am the only one to
react (so far!).

/Peter

Dilip

unread,
Sep 6, 2006, 3:14:45 PM9/6/06
to
kanze wrote:
> It sends the wrong message to the reader.
>
> When I see a reinterpret_cast in code, I immediately assume that
> there is something very delicate and implementation dependant
> going on. When I see a static_cast, I suppose that while you
> are subverting the type system somewhat, it is within more
> reasonable bounds, and is portable---I don't have to pay
> particular attention to it when porting to another system, for
> example.

There is a specific scenario that I have never been clear about in all
these years w.r.t reinterpret_casts.

In MSFT's COM-land, there is an API called CoCreateInstance -- its last
parameter is of type void**. This API is used to get a pointer to the
interface (abstract class to be precise) you are interested in. So
people always do something like this:

struct IUnknown
{
virtual void QueryInterface(REFIID riid, void** ppv) = 0;
virtual void AddRef() = 0;
virtual void Release() = 0;
};

struct ISomeInterface : public IUnknown
{
virtual void DoIt() = 0;
};

ISomeInterface* isi;
CoCreateInstance(......,...., reinterpret_cast<void**>(&isi));

Internally a lot of hocus-pocus happens and the API ends up calling an
implementation of a standard IUnknown method called QueryInterface that
returns a pointer to ISomeInterface like so:

class SomeInterfaceImpl : public ISomeInterface
{
void QueryInterface(REFIID riid, void** ppv)
{
*ppv = static_cast<ISomeInterface*>(this);

reinterpret_cast<IUnknown*>(*ppv)->AddRef();
}

// remaining implementations elided for clarity
};

Have the proper casts been used in the above code? Can you explain why
reinterpret_cast is needed in places where its been used?

Andrei Polushin

unread,
Sep 7, 2006, 9:45:18 AM9/7/06
to
Dilip wrote:
> ISomeInterface* isi;
> CoCreateInstance(......,...., reinterpret_cast<void**>(&isi));
> [...]

>
> Have the proper casts been used in the above code? Can you explain why
> reinterpret_cast is needed in places where its been used?

The code could be rewritten using static_cast:

void* pv;
CoCreateInstance(......,...., &pv);

ISomeInterface* isi = static_cast<ISomeInterface*>(pv);


--
Andrei Polushin

Joe

unread,
Sep 7, 2006, 9:46:28 AM9/7/06
to

Dilip wrote:
> In MSFT's COM-land, there is an API called CoCreateInstance -- its last
> parameter is of type void**. This API is used to get a pointer to the
> interface (abstract class to be precise) you are interested in. So
> people always do something like this:
>
> struct IUnknown
> {
> virtual void QueryInterface(REFIID riid, void** ppv) = 0;
> virtual void AddRef() = 0;
> virtual void Release() = 0;
> };
>
> struct ISomeInterface : public IUnknown
> {
> virtual void DoIt() = 0;
> };
>
> ISomeInterface* isi;
> CoCreateInstance(......,...., reinterpret_cast<void**>(&isi));
>
> Internally a lot of hocus-pocus happens and the API ends up calling an
> implementation of a standard IUnknown method called QueryInterface that
> returns a pointer to ISomeInterface like so:
>
> class SomeInterfaceImpl : public ISomeInterface
> {
> void QueryInterface(REFIID riid, void** ppv)
> {
> *ppv = static_cast<ISomeInterface*>(this);
>
> reinterpret_cast<IUnknown*>(*ppv)->AddRef();
> }
>
> // remaining implementations elided for clarity
> };
>
> Have the proper casts been used in the above code? Can you explain why
> reinterpret_cast is needed in places where its been used?
>

This is pretty system specific, so I don't know if this will go or not.
But, I think I can explain that. A COM object can implement many
independent interfaces as well as inherited interfaces and All
interfaces inherit from IUnknown. So, they end up constructing a
fairly fancy vtbl to implement all of this. The static_cast<> above
can move the pointer up and down the vtbl to the root of the
appropriate interface. The reinterpret_cast<> is then used to be sure
that the appropriate IUnknown will be invoked without further moving of
the pointer. I will try to draw a picture. If we have 2 interfaces,
we might have a vtbl that looks like this:

1: IUnknown
2: IInterface1
3: IUnknown
4: IInterface2

if we static cast to Interface2, the pointer will correspond to
position 3. When we invoke the IUnknown addref method, we want the
IUnknown from position 3 and not the IUnknown and position 1. To
indicate that there is something tricky going on and that we are
getting a specific IUnknown, they are using a reinterpret_cast.
Hopefully that sheds some light and isn't too far off base.

To bring it back to normal C++, we can imagine an interface like:

class base
{
virtual ~Base(){}
virtual void Print() = 0;
}

class IInterface1 : public Base
{
}

class IInterface2 : public Base
{
}

class Implement : public IInterface1, public IInterface2
{
}

Now, if we wanted to get a pointer to the Base that came with
IInterface2 we might static_cast to IInterface2 the reinterpret cast to
Base. I do not believe that the reinterpret_cast is required to do
this, but it does signal that something tricky is going on.

Hopefully, I haven't spread too many lies above, I have slept at least
once since doing any COM stuff. :)

joe

kanze

unread,
Sep 7, 2006, 9:51:59 AM9/7/06
to
peter koch larsen wrote:
> bjarne wrote:
> [SNIP]
> > Also, when you use static_cast, you stay within the
> > semantics of the language; when you use reinterpret_cast,
> > you play with bits (the representation). By doing
> > static_cast<int*>(pv) when pv is a void*, you assume that a
> > void* is represented in exactly the same ways as an int*.
> > That's by far the most common, but not guaranted.

> This statement scares me somewhat, but hopefully its just my
> understanding of english that suffers. static_casting from
> e.g. void* to int* can only be performed when the
> representation for void* is the same as for int* - and there
> is nothing that guarantees that this will work? So - by
> inference - malloc is not guaranteed to work? I surely must
> misunderstand something - and yet I am the only one to react
> (so far!).

I think that there was a type here as well, and that Bjarne was
in fact talking about reinterpret_cast. (Technically, the
mapping done by reinterpret_cast is implementation defined, and
an implementation could make it work here regardless. But the
statement "you play with bits" is, I think, an accurate informal
description of the intent of reinterpret_cast.)

--
James Kanze GABI Software

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

James Hopkin

unread,
Sep 7, 2006, 9:53:19 AM9/7/06
to

Dilip wrote:
>
> ISomeInterface* isi;
> CoCreateInstance(......,...., reinterpret_cast<void**>(&isi));
>

I believe you need more than the Standard guarantees for this to work.
A more conformant way would be

void* out_param;
CoCreateInstance(......,...., &out_param);
if (/* co-create succeeded */)
{
ISomeInterface* isi = static_cast<ISomeInterface*>(out_param);
// code using isi here
}

It also means you can't accidentally forget the & operator.

> Internally a lot of hocus-pocus happens and the API ends up calling an
> implementation of a standard IUnknown method called QueryInterface that
> returns a pointer to ISomeInterface like so:
>
> class SomeInterfaceImpl : public ISomeInterface
> {
> void QueryInterface(REFIID riid, void** ppv)
> {
> *ppv = static_cast<ISomeInterface*>(this);
>
> reinterpret_cast<IUnknown*>(*ppv)->AddRef();
> }
>
> // remaining implementations elided for clarity
> };
>

Don't all interfaces inherit IUnknown? If so, the reinterpret_cast
isn't needed at all (or a static_cast could be used just in case AddRef
has been hidden by ISomeInterface).

What I've said only addresses the casts used in a COM-like system. If I
remember correctly, to create real COM classes in C++, the compiler
needs to lay out the objects in a particular way. I've mostly seen
C-style casts in COM code; these work because of the extra requirements
COM places on the compiler's ABI. (You can create COM classes on other
compilers, but COM features won't map to C++ features. For example,
you'd have to create your own v-tables - that's how you write COM
classes in C).

James

kanze

unread,
Sep 7, 2006, 9:52:46 AM9/7/06
to

If the lvalue which *ppv designates does not have the type
void*, this is undefined behavior. You've lied to the compiler,
and the compiler has the right to punish you for it.

I am aware of implementations where a void* would be larger than
an ISomeInterface*. On such an implementation, Assuming that
ppv was initialized (indirectly) with the reinterpret_cast in
your call above, this line will write not just isi, but also
some bytes behind it. More generally, it will convert the
ISomeInterface* results of the cast to a void*, doing whatever
conversion is relevant for your machine, and then write the
results, as a void*, starting at the address of isi. If (as is
usually the case), void* and ISomeInterface* have the same size
and representation, everything will work fine; if they don't,
you're screwed.

About the only way to write this line in a way that is
guaranteed to work according to the C++ standard would be to
declare the parameter of CoCreateInstance to be a void* (which
eliminates the need of a cast when calling it), and then write:
*static_cast< ISomeInterface** >( ppv ) = this ;
here. Given the current interface, you need two pointers:
void * visi ;
ISomeInterface* isi ;
You then pass &visi to CoCreateInstance, and the above line is
valid. Later, when you want to use isi, you must static_cast
visi to ISomeInterface* and assign it to isi.

> reinterpret_cast<IUnknown*>(*ppv)->AddRef();

Same problem as above. Except that this will actually fail,
even on a PC, if multiple inheritance is involved. Even
assuming that all pointers have the same representation (which
the interface seems to do), the only valid reinterpret_cast of
*ppv is to the type of pointer that was actually stored there,
in this case, an ISomeInterface*.

> }
>
> // remaining implementations elided for clarity
> };

> Have the proper casts been used in the above code? Can you
> explain why reinterpret_cast is needed in places where its
> been used?

What does Microsoft say about it? There are definitly
architectures where this reinterpret_cast will NOT work, and
where it will get you into deep trouble. But what it actually
does is somewhere between implementation defined and undefined
behavior. If Microsoft says that it will work in this case,
then they are defining a legal extension to the language. If
you're using COM, you're using extensions to the language
anyway, and your code won't work on a lot of platforms.
Anything regarding the use of COM is Microsoft's call, not that
of the C++ standard. (The use of such techniques probably means
that COM cannot be implemented on a platform where void* and
SomeClass* have different representations. But presumably, that
is a limitation that Microsoft is willing to take.)

--
James Kanze GABI Software
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

Francis Glassborow

unread,
Sep 7, 2006, 10:28:14 AM9/7/06
to
In article <1157561346.5...@p79g2000cwp.googlegroups.com>,
peter koch larsen <peter.ko...@gmail.com> writes

>bjarne wrote:
>[SNIP]
>> Also, when you use static_cast, you stay within the semantics of the
>> language; when you use reinterpret_cast, you play with bits (the
>> representation). By doing static_cast<int*>(pv) when pv is a void*, you
>> assume that a void* is represented in exactly the same ways as an int*.
>> That's by far the most common, but not guaranted.
>
>This statement scares me somewhat, but hopefully its just my
>understanding of english that suffers. static_casting from e.g. void*
>to int* can only be performed when the representation for void* is the
>same as for int* - and there is nothing that guarantees that this will
>work? So - by inference - malloc is not guaranteed to work?
>I surely must misunderstand something - and yet I am the only one to
>react (so far!).


I suspect that under time pressure Bjarne has once again written
static_cast when he intended reinterpret_cast.


--
Francis Glassborow ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions:
http://www.spellen.org/youcandoit/projects

peter koch larsen

unread,
Sep 7, 2006, 2:28:17 PM9/7/06
to

kanze wrote:
> peter koch larsen wrote:
> > bjarne wrote:
> > [SNIP]
> > > Also, when you use static_cast, you stay within the
> > > semantics of the language; when you use reinterpret_cast,
> > > you play with bits (the representation). By doing
> > > static_cast<int*>(pv) when pv is a void*, you assume that a
> > > void* is represented in exactly the same ways as an int*.
> > > That's by far the most common, but not guaranted.
>
> > This statement scares me somewhat, but hopefully its just my
> > understanding of english that suffers. static_casting from
> > e.g. void* to int* can only be performed when the
> > representation for void* is the same as for int* - and there
> > is nothing that guarantees that this will work? So - by
> > inference - malloc is not guaranteed to work? I surely must
> > misunderstand something - and yet I am the only one to react
> > (so far!).
>
> I think that there was a type here as well, and that Bjarne was
> in fact talking about reinterpret_cast. (Technically, the
> mapping done by reinterpret_cast is implementation defined, and
> an implementation could make it work here regardless. But the
> statement "you play with bits" is, I think, an accurate informal
> description of the intent of reinterpret_cast.)

Okay - that was my original thought as well. I believe we can summarize
now that for a conversion from void* to e.g. int*, you must use
static_cast in order to be portable. This means I'll have to revise
some code - as I also used reinterpret_cast to do that trick (perhaps
inspired by bjarne as I used his books to learn C++ about 12 years
ago).

/Peter

bjarne

unread,
Sep 7, 2006, 2:44:53 PM9/7/06
to

peter koch larsen wrote:
> bjarne wrote:
> [SNIP]
> > Also, when you use static_cast, you stay within the semantics of the
> > language; when you use reinterpret_cast, you play with bits (the
> > representation).

So far so good.

> > By doing static_cast<int*>(pv) when pv is a void*, you
> > assume that a void* is represented in exactly the same ways as an int*.
> > That's by far the most common, but not guaranted.

Another typo. Sorry. I must stop posting while I'm drinking my first
cup of morning coffee (though when else do I find time?):

I meant *reinterpret_cast* in that statement.

Static_casts don't mess with representations, so your are protected
from all representation-related problems (though, as with every cast
there are some potential problems, or you wouldn't need a cast) whereas
reinterpret_casts do.

The point was exactly that *reinterpret_cast* simply reinterprets the
representation so that you are making assumptions about the
representation of both the type you cast from and the type you cast to.
Most people are a bit vague about what is and what is not guaranteed by
the language.


> This statement scares me somewhat, but hopefully its just my
> understanding of english that suffers. static_casting from e.g. void*
> to int* can only be performed when the representation for void* is the
> same as for int* - and there is nothing that guarantees that this will
> work? So - by inference - malloc is not guaranteed to work?
> I surely must misunderstand something - and yet I am the only one to
> react (so far!).
>
> /Peter
>

It was meant to scare you about *reinterpret_cast*. Reinterpret_cast
really is scary.

Use static_cast for malloc and you are as safe as you can ever be with
malloc().

-- Bjarne Stroustrup; http://www.research.att.com/~bs

kanze

unread,
Sep 8, 2006, 12:16:20 PM9/8/06
to
bjarne wrote:

> Static_casts don't mess with representations, so your are
> protected from all representation-related problems (though, as
> with every cast there are some potential problems, or you
> wouldn't need a cast) whereas reinterpret_casts do.

Still on that first cup of coffee, or have I misunderstood
something? A static_cast is almost required to modify the
representation in certain cases, and it is these modifications
which protect you, and make it work. Whereas on a normal
machine, provided the implementation respects the intent of the
standard, a reinterpret_cast will never change the
representation; the bits in the pointer stay the same,
regardless.

> The point was exactly that *reinterpret_cast* simply
> reinterprets the representation so that you are making
> assumptions about the representation of both the type you cast
> from and the type you cast to. Most people are a bit vague
> about what is and what is not guaranteed by the language.

My impression is that the standard itself is a bit vague about
what is guaranteed by reinterpret_cast. Intentionally, so that
an implementation can make it do something useful (and
"unsurprising to those who know the addressing structure of the
underlying machine") regardless of how bizarre the architecture.

--
James Kanze GABI Software

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

Lourens Veen

unread,
Sep 9, 2006, 3:09:15 PM9/9/06
to
kanze wrote:

> bjarne wrote:
>
>> Static_casts don't mess with representations, so your are
>> protected from all representation-related problems (though, as
>> with every cast there are some potential problems, or you
>> wouldn't need a cast) whereas reinterpret_casts do.
>
> Still on that first cup of coffee, or have I misunderstood
> something? A static_cast is almost required to modify the
> representation in certain cases, and it is these modifications
> which protect you, and make it work. Whereas on a normal
> machine, provided the implementation respects the intent of the
> standard, a reinterpret_cast will never change the
> representation; the bits in the pointer stay the same,
> regardless.

I read "Static_casts don't mess with representations" as "Static_casts
are not defined in terms of representation", hence on a conceptual
level they have nothing to do with representations, and so you (the
programmer) don't have to worry about them.

A static_cast converts a pointer of some type A pointing to an object
x into a pointer of some type B pointing to the same object x.
It "messes with" the type of the pointer, not with anything else. As
you say, the representation may or may not have to be changed
depending on the situation and the platform, but that is all taken
care of by the compiler, and is "under the hood" of the abstraction
provided by static_cast.

Lourens

James Dennett

unread,
Sep 9, 2006, 4:09:35 PM9/9/06
to
kanze wrote:
> bjarne wrote:
>
>> Static_casts don't mess with representations, so your are
>> protected from all representation-related problems (though, as
>> with every cast there are some potential problems, or you
>> wouldn't need a cast) whereas reinterpret_casts do.
>
> Still on that first cup of coffee, or have I misunderstood
> something? A static_cast is almost required to modify the
> representation in certain cases, and it is these modifications
> which protect you, and make it work. Whereas on a normal
> machine, provided the implementation respects the intent of the
> standard, a reinterpret_cast will never change the
> representation; the bits in the pointer stay the same,
> regardless.

I think it's a terminology thing; static_cast is defined
in terms of _values_, not representations, whereas in
most cases reinterpret_cast is implemented as identity
of _representations_ (though, as you said, the standard
doesn't require much of reinterpret_cast, and only alludes
indirectly to it not affecting representations).

-- James

Francis Glassborow

unread,
Sep 9, 2006, 6:11:29 PM9/9/06
to
In article <8e1a2$45027798$8259a2fa$27...@news1.tudelft.nl>, Lourens
Veen <lou...@rainbowdesert.net> writes

>A static_cast converts a pointer of some type A pointing to an object
>x into a pointer of some type B pointing to the same object x.
>It "messes with" the type of the pointer, not with anything else. As
>you say, the representation may or may not have to be changed
>depending on the situation and the platform, but that is all taken
>care of by the compiler, and is "under the hood" of the abstraction
>provided by static_cast.

No, not exactly true. If a class has multiple bases, a static cast can
be used to point to any of the base class objects and those will not all
share an address with the complete object.

--
Francis Glassborow ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions:
http://www.spellen.org/youcandoit/projects

bjarne

unread,
Sep 9, 2006, 8:55:27 PM9/9/06
to
{ Quoted clc++m banner removed. -mod }

kanze wrote:
> bjarne wrote:
>
> > Static_casts don't mess with representations, so your are
> > protected from all representation-related problems (though, as
> > with every cast there are some potential problems, or you
> > wouldn't need a cast) whereas reinterpret_casts do.
>
> Still on that first cup of coffee, or have I misunderstood
> something? A static_cast is almost required to modify the
> representation in certain cases, and it is these modifications
> which protect you, and make it work. Whereas on a normal
> machine, provided the implementation respects the intent of the
> standard, a reinterpret_cast will never change the
> representation; the bits in the pointer stay the same,
> regardless.

No, not the coffee (or lack thereof) this time :-)

I guess I should have said that reinterpret_cast "messes with the
meaning of representations" (rather than just "messing with
repesentations"). Static_cast manipulates values according to the type
rules of the language. Reinterpret cast does not. Consider:

int main()
{
int i = 2;
int* pi = &i;
double* dp = reinterpret_cast<double*>(pi);
}

The value of *dp is quite unlikely to be 2.0.


> > The point was exactly that *reinterpret_cast* simply
> > reinterprets the representation so that you are making
> > assumptions about the representation of both the type you cast
> > from and the type you cast to. Most people are a bit vague
> > about what is and what is not guaranteed by the language.
>
> My impression is that the standard itself is a bit vague about
> what is guaranteed by reinterpret_cast. Intentionally, so that
> an implementation can make it do something useful (and
> "unsurprising to those who know the addressing structure of the
> underlying machine") regardless of how bizarre the architecture.

Exactly. Reinterpret_casts is what you use as a last resort, making
assumptions about the machine. You can get into trouble with
static_cast (as with all cast), but reinterpret_cast is provided for
the cases where the compiler can provide essentially no help. An
experienced programmer may till be able to do something useful based on
knowledge of the machine.

-- Bjarne Stroustrup; http://www.research.att.com/~bs

James Dennett

unread,
Sep 10, 2006, 6:32:41 AM9/10/06
to
Francis Glassborow wrote:
> In article <8e1a2$45027798$8259a2fa$27...@news1.tudelft.nl>, Lourens
> Veen <lou...@rainbowdesert.net> writes
>> A static_cast converts a pointer of some type A pointing to an object
>> x into a pointer of some type B pointing to the same object x.
>> It "messes with" the type of the pointer, not with anything else. As
>> you say, the representation may or may not have to be changed
>> depending on the situation and the platform, but that is all taken
>> care of by the compiler, and is "under the hood" of the abstraction
>> provided by static_cast.
>
> No, not exactly true. If a class has multiple bases, a static cast can
> be used to point to any of the base class objects and those will not all
> share an address with the complete object.
>

I believe that is consistent with the latter part of the
post to which you were replying, which did say

> the representation may or may not have to be changed
> depending on the situation and the platform, but that
> is all taken care of by the compiler, and is "under
> the hood" of the abstraction provided by static_cast

However, the sentence

> It "messes with" the type of the pointer, not with anything else.

was somewhat unfortunate, and more descriptive of typical
implementations of reinterpret_cast than of static_cast.

-- James

Lourens Veen

unread,
Sep 10, 2006, 6:36:49 AM9/10/06
to
Francis Glassborow wrote:

> In article <8e1a2$45027798$8259a2fa$27...@news1.tudelft.nl>, Lourens
> Veen <lou...@rainbowdesert.net> writes
>>A static_cast converts a pointer of some type A pointing to an
>>object x into a pointer of some type B pointing to the same object
>>x. It "messes with" the type of the pointer, not with anything else.
>>As you say, the representation may or may not have to be changed
>>depending on the situation and the platform, but that is all taken
>>care of by the compiler, and is "under the hood" of the abstraction
>>provided by static_cast.
>
> No, not exactly true. If a class has multiple bases, a static cast
> can be used to point to any of the base class objects and those will
> not all share an address with the complete object.

I was considering them all to be the same object, but I'm not sure
whether that is accepted terminology. I think that we need to make a
clear distinction between the value of a variable and its
representation. Consider

struct A { /* ... */ }
struct B { /* ... */ }
struct C : public A, public B { /* ... */ }

int main() {
C c;
C * cp = &c;
A * ap = static_cast<A *>(&c);
B * bp = static_cast<B *>(&c);
}

If I call a member function on c through cp that modifies some
variable in the B subobject of c, then I will be able to see that
change through bp. So, conceptually, I'd argue that all the pointers
point to the same object.

In other words, the result of static_cast<B *>(&c) is a pointer of
type B * that points to c. The only difference between &c and
static_cast<B *>(&c) is that the type of the first expression is C *,
and the type of the second expression is B *. Their _value_ is the
same, namely "pointer to c", their types are different.

Now, most (all?) machines represent pointers as memory addresses. The
exact mapping between a pointer value and its representation depends
on the type of the pointer value and the type of the object it points
to. Depending on the compiler and the machine, bp may well have to
have a different representation than cp, even though they point to
the same object c (e.g. so that it stores the address of the
subobject of c of type B). So, static_cast may have to return a
different representation to ascertain that it returns the same value,
depending on the types it's casting from and to.

The language doesn't say anything about what the representation for &c
looks like however, and it doesn't specify whether static_cast
changes the representation or not. All it guarantees is that the
value remains the same, so that you can safely access c through bp.

Mr. Stroustrup expressed that (somewhat imprecisely) as "Static_casts
don't mess with representations". Perhaps "Static_casts don't deal
with representations, only with types and values. An implementation
of static_cast may change the representation to satisfy the
constraints on the value." would be a better description.

Lourens

Francis Glassborow

unread,
Sep 10, 2006, 10:57:22 AM9/10/06
to
In article <c4dea$4503d67b$8259a2fa$59...@news2.tudelft.nl>, Lourens Veen
<lou...@rainbowdesert.net> writes

>struct A { /* ... */ }
>struct B { /* ... */ }
>struct C : public A, public B { /* ... */ }
>
>int main() {
> C c;
> C * cp = &c;
> A * ap = static_cast<A *>(&c);
> B * bp = static_cast<B *>(&c);
>}
>
>If I call a member function on c through cp that modifies some
>variable in the B subobject of c, then I will be able to see that
>change through bp. So, conceptually, I'd argue that all the pointers
>point to the same object.
>
>In other words, the result of static_cast<B *>(&c) is a pointer of
>type B * that points to c. The only difference between &c and
>static_cast<B *>(&c) is that the type of the first expression is C *,
>and the type of the second expression is B *. Their _value_ is the
>same, namely "pointer to c", their types are different.


Sorry, IMHO that way madness lies. bp is a pointer to some B object or
subobject. The above code initialises it to a subobject of c. But we can
latter change it to point to some other B object. It does not inherently
point into a C object.

At best, after the initialisation above we can say that bp points into
c. Note that I can make the problem even more severe by using a virtual
base class.

--
Francis Glassborow ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions:
http://www.spellen.org/youcandoit/projects

Lourens Veen

unread,
Sep 10, 2006, 2:13:31 PM9/10/06
to
Francis Glassborow wrote:

> In article <c4dea$4503d67b$8259a2fa$59...@news2.tudelft.nl>, Lourens
> Veen <lou...@rainbowdesert.net> writes
>>struct A { /* ... */ }
>>struct B { /* ... */ }
>>struct C : public A, public B { /* ... */ }
>>
>>int main() {
>> C c;
>> C * cp = &c;
>> A * ap = static_cast<A *>(&c);
>> B * bp = static_cast<B *>(&c);
>>}
>>
>>If I call a member function on c through cp that modifies some
>>variable in the B subobject of c, then I will be able to see that
>>change through bp. So, conceptually, I'd argue that all the pointers
>>point to the same object.
>>
>>In other words, the result of static_cast<B *>(&c) is a pointer of
>>type B * that points to c. The only difference between &c and
>>static_cast<B *>(&c) is that the type of the first expression is C
>>*, and the type of the second expression is B *. Their _value_ is
>>the same, namely "pointer to c", their types are different.
>
>
> Sorry, IMHO that way madness lies. bp is a pointer to some B object
> or subobject. The above code initialises it to a subobject of c. But
> we can latter change it to point to some other B object. It does not
> inherently point into a C object.

Maybe I'm mad then :). For what it's worth:

C is derived from B, so every C is a B. Hence c is a B, and bp can
point to it. If it does, bp probably won't hold the address of c but
some address inside c, but that doesn't make a difference
conceptually.

I know that C++ inheritance is not a strict type/subtype relationship
and that it violates the Liskov substitution principle, but I don't
think the idea is that outlandish.

Also, if B defined a virtual member function B::f() that was
overridden by C, how would you explain C::f() being called by bp->f()
if bp is pointing to a B subobject and doesn't know anything about
the C object that that B subobject it points to is part of?

I don't disagree with you that the address contained in bp may be
different from that contained in cp. It makes sense to implement it
that way and most if not all compilers do that. The problem is, we're
thinking on different levels. I'm talking about abstract concepts,
while you are talking about how they are implemented. The whole point
of static_cast over reinterpret_cast is that static_cast is defined
on that conceptual level, while reinterpret_cast requires knowledge
of implementation detail. That makes static_cast less dangerous than
reinterpret_cast.

Lourens

James Hopkin

unread,
Sep 11, 2006, 9:34:37 AM9/11/06
to

Francis Glassborow wrote:
> In article <c4dea$4503d67b$8259a2fa$59...@news2.tudelft.nl>, Lourens Veen
> <lou...@rainbowdesert.net> writes
> >struct A { /* ... */ }
> >struct B { /* ... */ }
> >struct C : public A, public B { /* ... */ }
> >
> >int main() {
> > C c;
> > C * cp = &c;
> > A * ap = static_cast<A *>(&c);
> > B * bp = static_cast<B *>(&c);
> >}

<snip>

> >In other words, the result of static_cast<B *>(&c) is a pointer of
> >type B * that points to c. The only difference between &c and
> >static_cast<B *>(&c) is that the type of the first expression is C *,
> >and the type of the second expression is B *. Their _value_ is the
> >same, namely "pointer to c", their types are different.
>
>
> Sorry, IMHO that way madness lies. bp is a pointer to some B object or
> subobject. The above code initialises it to a subobject of c. But we can
> latter change it to point to some other B object. It does not inherently
> point into a C object.
>
> At best, after the initialisation above we can say that bp points into
> c. Note that I can make the problem even more severe by using a virtual
> base class.
>

I think it depends on the style of the code. If B was designed as a
polymorphic base class (or interface), surely the only valid way to
think of bp is that it 'points to c'. I think the normal way of writing
the code:

B* bp = &c;

says that pretty clearly.

It does rely on B and C conforming to OO conventions, and of course
there are other ways of using inheritance in C++, such as
implementation (boost::iterator_facade is my favourite example). In
those cases, though, you wouldn't normally have a pointer or reference
to base in client code. The base is just an implementation detail (and
the compiler-provided conversion unfortunate, but not a problem in
practice).


James

ThosRTanner

unread,
Sep 12, 2006, 6:42:54 AM9/12/06
to

kanze wrote:
> Diego Martins wrote:
>
> > But it is WRONG to use reinterpret_cast in this example?
> > In my programs, I use reinterpret_cast to cast to void * and cast back
> > to the original pointer type.
> > Are there any drawbacks using this approach? What does static_cast buy
> > me in this case?

>
> It sends the wrong message to the reader.
>
> When I see a reinterpret_cast in code, I immediately assume that
> there is something very delicate and implementation dependant
> going on. When I see a static_cast, I suppose that while you
> are subverting the type system somewhat, it is within more
> reasonable bounds, and is portable---I don't have to pay
> particular attention to it when porting to another system, for
> example.
>
Whenever I see a reinterpret cast in our code, I know someone is doing
a tremendous hack. I've come accross places where 5 consecutive lines
of code with 3 reinterpret_cast's in them. A little thought would have
eliminated all 3 of them.

There are times when I wish the standards comittee had called
reinterpret_cast something more thought provoking, like (say)
I_understand_what_I_am_doing_is_actually_a_tremendous_hack_and_is_unlikely_to_work_if_almost_anything_changes_cast

and banned C-style casts entirely


It seems to be all to easy to write reinterpret_cast rather thank
applying the gray matter.

bjarne

unread,
Sep 12, 2006, 2:25:51 PM9/12/06
to

ThosRTanner wrote:

> Whenever I see a reinterpret cast in our code, I know someone is doing
> a tremendous hack. I've come accross places where 5 consecutive lines
> of code with 3 reinterpret_cast's in them. A little thought would have
> eliminated all 3 of them.
>
> There are times when I wish the standards comittee had called
> reinterpret_cast something more thought provoking, like (say)
>
I_understand_what_I_am_doing_is_actually_a_tremendous_hack_and_is_unlikely_t
o_work_if_almost_anything_changes_cast

:-) "reinterpret_cast" is already pretty long/LOUD compared to the
average C++ keyword.


> and banned C-style casts entirely

I proposed deprecation of C-style casts, but I could not get consensus
for that in the committee.


> It seems to be all to easy to write reinterpret_cast rather thank
> applying the gray matter.

and even easier to write a C-style cast.

-- Bjarne Stroustrup; http://www.research.att.com/~bs

andre...@yahoo.com

unread,
Sep 12, 2006, 5:13:44 PM9/12/06
to

bjarne wrote:
> I proposed deprecation of C-style casts, but I could not get consensus
> for that in the committee.

Isn't a C-style cast appropriate for casting integer types:

long long a = 1;
int b = (int)a;
short c = (short)b;

Frederick Gotham

unread,
Sep 12, 2006, 7:27:00 PM9/12/06
to
andre...@yahoo.com posted:

> Isn't a C-style cast appropriate for casting integer types:
>
> long long a = 1;
> int b = (int)a;
> short c = (short)b;


I would agree on this point, I commonly do such things as:

unsigned i = (char unsigned)-1;

--

Frederick Gotham

Gabriel Dos Reis

unread,
Sep 12, 2006, 7:26:24 PM9/12/06
to
"andre...@yahoo.com" <andre...@yahoo.com> writes:

| bjarne wrote:
| > I proposed deprecation of C-style casts, but I could not get consensus
| > for that in the committee.
|
| Isn't a C-style cast appropriate for casting integer types:
|
| long long a = 1;
| int b = (int)a;
| short c = (short)b;

yes, but you would do the same with a less catch-all syntax.

Notice that, in C++, the semantics of C-style cast is defined in terms of
those of new-style casts.

--
Gabriel Dos Reis
g...@integrable-solutions.net

Bjørn Roald

unread,
Sep 12, 2006, 7:48:29 PM9/12/06
to
andre...@yahoo.com skrev:

> Isn't a C-style cast appropriate for casting integer types:
>
> long long a = 1;
> int b = (int)a;
> short c = (short)b;
>

I don't know about you, but I would have written:

long long a = 1;

int b = a;
short c = b;

or,

long long a = 1;

int b(a);
short c(b);

or,

long long a = 1;

int b = int(a);
short c = short(b);

I don't think there is anything I would miss if the C style cast where gone.

-----
Bjørn Roald

Frederick Gotham

unread,
Sep 12, 2006, 11:50:29 PM9/12/06
to
Bjørn Roald posted:

> I don't know about you, but I would have written:
>
> long long a = 1;
> int b = a;
> short c = b;


You'll get compiler warnings.


> or,
>
> long long a = 1;
> int b(a);
> short c(b);


Again, you'll get compiler warnings.

> or,
>
> long long a = 1;
> int b = int(a);
> short c = short(b);


Those directly above are C-style casts -- they're just dressed up to look
pretty.

--

Frederick Gotham

Bjørn Roald

unread,
Sep 13, 2006, 9:36:49 AM9/13/06
to
Frederick Gotham skrev:

> Bjørn Roald posted:
>
>> I don't know about you, but I would have written:
>>
>> long long a = 1;
>> int b = a;
>> short c = b;
>
>
> You'll get compiler warnings.
>
>
>> or,
>>
>> long long a = 1;
>> int b(a);
>> short c(b);
>
>
> Again, you'll get compiler warnings.
>

May very well be true that you get warnings on some compilers, but:

#include <iostream>
int main()
{


long long a = 1;

std::cout << "Enter a (long long) number: ";
std::cin >> a;
if( std::cin )
{


int b = (int)a;
short c = (short)b;

int bb = a;
short cc = b;

int bbb = int(a);
short ccc = short(b);

int bbbb(a);
short cccc(b);

int bbbbb = static_cast<int>(a);
short ccccc = static_cast<short>(b);

std::cout << a << ' '
<< b << ' '
<< c << ' '
<< bb << ' '
<< cc << ' '
<< bbb << ' '
<< ccc << ' '
<< bbbb << ' '
<< cccc << ' '
<< bbbbb << ' '
<< ccccc << '\n';
}
else
{
std::cout << std::endl <<
"are you sure that was a long long integer?" << std::endl;
}
return 0;
}

compiled like this:

g++ -Wall casts.cpp -o casts

produces no warnings.


My concern however (and you cut out some context here) is whether this
is not equally or more appropriate for the obviously intended result
than C-style casts. I fail to see how the compiler can help you any
more with a C-style cast. Hence the only thing you archive with C-style
cast here is to disable your compilers chance to warn you, you tell it
to trust you. And you are doing it in a way that is hard to spot for
readers of your code or simple tools. Sometimes that warning may come in
handy to people including yourselves dealing with the code later.

On the other hand, since tools like g++ produce no warning. Then a very
clear way to declare the cast in the code is to use static_cast. E.g.
if you are looking through code for potential trouble spots, then you
could search for '_cast', have you ever tried to search for C-style
casts, or any of those other implicit casts I suggested above.

>
>
>> or,
>>
>> long long a = 1;
>> int b = int(a);
>> short c = short(b);
>
>
> Those directly above are C-style casts -- they're just dressed up to look
> pretty.

I like the look of them better, yes :-). If removing C-style cast from
the standard in the distant future would take these away, then I think I
would miss this feature a bit.


---
Bjørn Roald

Francis Glassborow

unread,
Sep 13, 2006, 9:41:05 AM9/13/06
to
In article <rtGNg.13647$j7.3...@news.indigo.ie>, Frederick Gotham
<fgot...@SPAM.com> writes

>andre...@yahoo.com posted:
>
>> Isn't a C-style cast appropriate for casting integer types:
>>
>> long long a = 1;
>> int b = (int)a;
>> short c = (short)b;
>
>
>I would agree on this point, I commonly do such things as:
>
> unsigned i = (char unsigned)-1;

The only reason I would consider this is for C compatibility. However I
must confess there is a single exception in my style, I happily use and
advocate the use of a function style cast (OK not quite a c-style cast)
for converting the value of an expression to an enum.

enum color {black, red, green, blue, white = 7};

color c;
c = color(red + green);

--
Francis Glassborow ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

kanze

unread,
Sep 13, 2006, 12:06:39 PM9/13/06
to
andre...@yahoo.com wrote:
> bjarne wrote:
> > I proposed deprecation of C-style casts, but I could not get
> > consensus for that in the committee.

> Isn't a C-style cast appropriate for casting integer types:

> long long a = 1;
> int b = (int)a;
> short c = (short)b;

Well, it's always a question of style, but... there are three
types of casts in C++: the "new" style, functional style, and
the old C style. I don't see any problem in using the
functional style when the intent is clearly to create a new
object:

f( MyClass( a ) ) ;

; in addition, they are the only type which works if the number
of arguments needed to create the new object isn't exactly 1.

(For that reason, I'd much rather see them called something else
in the standard, like "explicit creation of a temporary". And
also that such an expression wouldn't use a user defined
conversion operator---I suspect that most people would be
surprised if this expression called a.operator MyClass(), which
it can.)

Given that, I'd also write (or prefer to see):

long long a = 1 ;

int b = (long long)( a ) ;
{{ the poster most likely intended "int b = int( a ) ;" -mod }}
short c = short( b ) ;
// or (short)( b )...

Formally, as soon as the typename is in parentheses (and if the
typename requires more than one symbol, it must be in
parentheses), we have a C style cast, and not a function style
cast. But I think that in terms of what the reader understands:
as soon as what is being converted is in parentheses, I see the
explicit creation of a temporary. (But maybe that's just me.)

And I would never accept such conversions where pointers or
references were involved (even though technically, a pointer is
an object, and you can create a temporary which has a pointer
type just like you can create any other temporary).

Given the ambiguities that the function style cast creates, it
would probably have been better to have only the new style cast,
and an "explicit creation of a temporary" expression, in which
the type of the temporary must be in parentheses, but in which
the number (and type) of parameters must correspond to an
available constructor (and of course, all of the available
constructors for int take a single parameter). But of course,
it's too late for that now, and given the historical context, I
don't see how anyone could have had the idea when it would have
been possible.

--
James Kanze GABI Software
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

andre...@yahoo.com

unread,
Sep 13, 2006, 12:08:56 PM9/13/06
to

ThosRTanner wrote:
>
> It seems to be all to easy to write reinterpret_cast rather thank
> applying the gray matter.
>

Can someone help me with the gray matter here?
I am using anti-bloat techniques with arrays of pointers in a template
class.
What I need to do is equivalent to the following intent:

void** vbase = ...;
int** ibase = some_cast<int**>(vbase);

What cast am I supposed to use in view of the above. Are these
compatible
types for a static_cast?

-Andy

andre...@yahoo.com

unread,
Sep 13, 2006, 12:30:22 PM9/13/06
to
{ this is a clarification of an earlier post, it seems. if you happen
to be still thinking how to answer the first one, perhaps you should
reply to this one instead. thanks! -mod }

I have a question that relates to the original topic of whether there
is a good case for reinterpret_cast.

In my anti-bloat template for an Array<T>, I detect when T is a pointer
and use a void** to hold the base of the array. The problem is that my
operator[] needs to return a reference to T, rather than a pointer,
because I want to use ar[N] on both lhs and rhs. The conundrum is
equivalent to the following snippet:

void** base = ...;
int index = ...;
int*& val = static_cast<int*&>(base[index]); //illegal!!!

Note that the last line is the equivalent of what I want for an
operator [] that returns T&. My guess is that both C-style casts and
reinterpret_casts "work" for the same reasons, but both are
undersirable according to this thread. So what is the solution?

Andy

Diego Martins

unread,
Sep 13, 2006, 2:38:44 PM9/13/06