When reading about const_cast I came across sentences like the following:
Only the following conversions can be done with const_cast. In particular, only const_cast may be used to cast away (remove) constness or volatility.
1) Two possibly multilevel pointers to the same type may be converted between each other, regardless of cv-qualifiers at each level.
I've googled around a bit already and haven't found any concise, straightforward definitions of what a multilevel pointer is. So: what exactly is a multilevel pointer?
(Possible face-palm moment) It it just a pointer to a pointer, or pointer to a pointer to a pointer, e.g. int ** or int ***?
Is it just a pointer to a pointer, or pointer to a pointer to a pointer, e.g. int ** or int ***?
It is exactly this, yes.
Related
Here's some code from the PhysX examples:
std::vector<PxRigidActor*> actors(nbActors);
scene->getActors(PxActorTypeFlag::eRIGID_DYNAMIC | PxActorTypeFlag::eRIGID_STATIC,
reinterpret_cast<PxActor**>(&actors[0]), nbActors);
And then in the code of the getActors function they use it like this:
PxU32 NpScene::getActors(PxActorTypeFlags types, PxActor** buffer, PxU32 bufferSize, PxU32 startIndex=0) const
{
...
if ((types & PxActorTypeFlag::eRIGID_STATIC ) && mRigidActors[i]->is<PxRigidStatic>())
{
if (virtualIndex >= startIndex)
buffer[writeCount++] = mRigidActors[i];
virtualIndex++;
}
else if ((types & PxActorTypeFlag::eRIGID_DYNAMIC) && mRigidActors[i]->is<PxRigidDynamic>())
{
if (virtualIndex >= startIndex)
buffer[writeCount++] = mRigidActors[i];
virtualIndex++;
}
...
}
mRigidActors is defined as Ps::Array<PxRigidActor*>
The inheritance diagram looks like this:
So, my questions are:
I heard that the pointer to the parent class can point to the instance of the child class. Then, why do we need any casting at all? I tried, but without casting it doesn't work.
Is it safe to use reinterpret_cast as it is used here?
(I suppose yes, because it's just pointers conversion)
Is there a better solution?
I heard that the pointer to the parent class can point to the instance of the child class. Then, why do we need any casting at all? I tried, but without casting it doesn't work.
There is an implicit conversion from PxRigidActor* to PxActor* (a derived-to-base pointer conversion), but there is no such relationship between PxRigidActor** and PxActor**
Is it safe to use reinterpret_cast as it is used here? (I suppose yes, because it's just pointers conversion)
The cast is not itself unsafe, but it is undefined behaviour to dereference the pointer created by the cast.
Is there a better solution?
Define actors with an appropriate type in the first place, i.e.
std::vector<PxActor*> actors(nbActors);
scene->getActors(PxActorTypeFlag::eRIGID_DYNAMIC | PxActorTypeFlag::eRIGID_STATIC, actors.data(), nbActors);
You can then static_cast<PxRigidActor*> the elements of actors as needed.
reinterpret_cast<PxActor**>(&actors[0])
is casting the address of the first element of the vector, not casting the element itself.
Furthermore, the called function is treating the pointer as an array. That is, it is casting the .data() of the vector to a different type of element.
You would expect static_cast to be used when navigating between base/derived class references or pointers. But that highlights an issue: The cast might modify the address, if the base class instance is not at the beginning of the derived class! The reinterpet_cast avoids this and just changes the type without changing the value... but if such a value change was necessary, this code would not work right anyway. By casting the "out" parameter's address instead of the value in that address, the code has no idea that anything stored in that slot needs to be adjusted back to the real type.
Since he's casting a pointer to the pointer, the static_cast would not work directly in the same place. It's a double pointer, and that doesn't follow the rule of D* to B*. It would have to write the static_cast
as a reference cast, and then take the address of that. Off the top of my head, something like &static_cast<PxActor*&>(actors.data()) (that might have the same issue; I'd have to bang on it to get something working, probably not as a single expression; and I have no intention of trying to do that.)
My guess is that he converted a legacy C cast to reinterpet_cast and didn't think too much about it, or saw that only this one worked (in the same place as the legacy cast).
but why?
The code populates a contiguous collection of the base class pointer. It takes an out parameter instead of returning a vector, and the caller wants that vector defined as a derived type instead of the base type. Normally it should be just fine to keep it as the base class since the behavior is presumably polymorphic.
This is copying from different source collections, with identical code in each branch. It probably ought to be generic, or use the visitor pattern. That would avoid most of the type casting issues.
From Programming Language Pragmatics, by Scott
For systems programming, or to facilitate the writing of
general-purpose con- tainer (collection) objects (lists, stacks,
queues, sets, etc.) that hold references to other objects, several
languages provide a universal reference type. In C and C++, this
type is called void *. In Clu it is called any; in Modula-2,
address; in Modula-3, refany; in Java, Object; in C#, object.
In C and C++, how does void * work as a universal reference type?
void * is always only a pointer type, while a universal reference type contains all values, both pointers and nonpointers. So I can't see how void * is a universal reference type.
Thanks.
A void* pointer will generally hold any pointer that is not a C++ pointer-to-member. It's rather inconvenient in practice, since you need to cast it to another pointer type before you can use it. You also need to convert it to the same pointer type that it was converted from to make the void*, otherwise you risk undefined behavior.
A good example would be the qsort function. It takes a void* pointer as a parameter, meaning it can point to an array of anything. The comparison function you pass to qsort must know how to cast two void* pointers back to the types of the array elements in order to compare them.
The crux of your confusion is that neither an instance of void * nor an instance of Modula-3's refany, nor an instance of any other language's "can refer to anything" type, contains the object that it refers to. A variable of type void * is always a pointer and a variable of type refany is always a reference. But the object that they refer to can be of any type.
A purist of programming-language theory would tell you that C does not have references at all, because pointers are not references. It has a nearly-universal pointer type, void *, which can point to an object of any type (including integers, aggregates, and other pointers). As a common but not ubiquitous extension, it can also point to any function (functions are not objects).
The purist would also tell you that C++ does not have a (nearly-)universal pointer type, because of its stricter type system, and doesn't have a universal reference type either.
They would also say that the book you are reading is being sloppy with its terminology, and they would caution you to not take any one such book for the gospel truth on terminological matters, or any other matters. You should instead read widely in both books and CS journals and conference proceedings (collectively known as "the literature") until you gain an "ear" for what is generally-agreed-on terminology, what is specific to a subdiscipline or a community of practice, and so on.
And finally they would remind you that C and C++ are two different languages, and anyone who speaks of them in the same breath is either glossing over the distinctions (which may or may not be relevant in context), decades out of date, or both.
Probably the reason is that you can take address of any variable of any type and cast it to void*.
It does by a silent contract that you know the actual type of object.
So you can store different kinds of elements in a container, but you need to somehow know what is what when taking elements back, to interpret them correctly.
The only convenience void* offers is that it's idiomatic for this, i.e. it's clear that dereferencing the pointer makes no sense, and void* is implicitly convertible to any pointer type. That is for c/
In c++ this is called type erasure techniques preferred. Or special types, like any (there is a boost version of this too.)
void* is no more just a pointer. Thus, it holds an address of an object (or an array and stuffs like that)
When your program is running, every variable should have it owns address in memory, right? And pointer is somethings point to that address.
In normal, each type of pointer should be the same type of object int b = 5; int* p = &b; for example. But that is the case you know what the type is, it means the specific type.
But sometimes, you just want to know that it stores somethings somewhere in memory and you know what "type" of that address, you can cast easily. For example, in OpenCV library which I am learning, there are a lot of functions where user can pass the arguments to instead of declaring global variables and most use in callback functions, like this:
void onChange(int v, void *ptr)
Here, the library does not care about what ptr point to, it just know that when you call the function, if you pass an address to like this onChange(5,&b) then you must cast ptr to the same type before dealing with it int b = static_cast<int*>(ptr);
Probably this explanation from Understanding pointers from Richard Reese will help
A pointer to void is a general-purpose pointer used to hold references to any data type.
It has two interesting properties:
A pointer to void will have the same representation and memory alignment as a pointer to char
A pointer to void will never be equal to another pointer. However, two void pointers assigned a NULL value will be equal.
Any pointer can be assigned to a pointer to void. It can then be cast back to its original pointer type. When this happens the value will be equal to the original pointer value.
This is illustrated in the following sequence, where a pointer to
int is assigned to a pointer to void and then back to a pointer to int
#include<stdio.h>
void main()
{
int num = 100;
int *pi = #
printf("value of pi is %p\n", pi);
void* pv = pi;
pi = (int*)pv;
printf("value of pi is %p\n", pi);
}
Pointers to void are used for data pointers, not function pointers
I have a const pointer to a pointer to a Fred and I don't understand why a static_cast isn't sufficient.
typedef struct {
int n;
} Fred;
Fred *pFred;
Fred **const ppFred = &pFred;
void **const ppVoid = static_cast<void ** const>(ppFred);
Please could someone explain why a reinterpret_cast is needed to convert a pointer to Fred*to a pointer to void* but static_cast is fine to convert pointer to Fred to a pointer to void.
There's no requirement that a Fred* and a void* have the same size
and representation. (I've worked on machines where they didn't,
although that was before my C++ days.) When you convert Fred* to
void*, you get a new pointer, with a possibly different size and
representation, but there is no information about the size and
representation of the object the void* points to. You know that it is
unknown, and the only way to use this void* is to cast it back to a
Fred* (modulo things like cv-qualifiers). When you convert Fred**
to void**, you're converting from a pointer to a concrete type (a
pointer to a Fred*) to a pointer to another concrete type (a pointer
to a void*). And since there's no guarantee that these two concrete
types have the same size and representation, the conversion requires a
reinterpret_cast. void is a special, non-concrete type, so you can
static_cast a pointer to any type to and from a pointer to void.
void* is just another concrete pointer type, so casting to and from
pointers to it follows the usual rules (and requires a
reinterpret_cast).
In many ways, the situation is very much like int and double, where
void* plays the role of int (say), and Fred* the role of double.
There's no problem static_casting between int and double, but
casts between int* and double* require reinterpret_cast.
All object pointers are convertible to void*, so a static cast is fine for that. However, converting between T* and U* in general requires a reinterpret cast, since arbitrary pointers are not mutually convertible. (And substitute T = Fred*, U = void*.)
static_cast won't work to convert Fred ** to void ** because it's not a sensible conversion : the pointers to Fred* and to void* are not necessarily created the same way (i.e. alignments problems on some platforms). You can be sure that a void* which can point to any byte in memory can point to a Fred object as well, but that's not the case for void** pointers.
Disclaimer
The following is hand-waving for the purpose of making things easily understood, not a technically correct description.
The hand-waving
One possible way to introduce void is:
void is similar (not the same thing as) the Java Object universal superclass.
void can be seen as an abstract base of every class and non-class type. (With this metaphor, void would also be a quasi-virtual base type: conversion to void* is never ambiguous.)
So you can see the implicit conversion from T* to void* as a derived-to-base conversion, and the reverse static_cast is like a base to derived down-cast. When a void* does not really point to a T, you should not do a static_cast<T*> (when a Base* does not really point to a Derived, you should not do a static_cast<Derived*>).
Disclaimer, again
Seriously, void is not an abstract base class, and cannot be formally treated as one in many cases:
You cannot formally describe void either as a virtual base (or static_cast would break) or a non-virtual base (or conversions to void* would be ambiguous when multiple inheritance is used).
There is no void& type. This base class metaphor just does extend beyond pointers.
Please, DO NOT go tell people "void is the universal C++ base class, like Java Object". Do not repeat anything I wrote here without the full disclaimers.
Only in some cases, void behaves like a base class for the purpose of pointer implicit conversions and casts.
You cannot write programs based on metaphors, but on the real C++ rules.
This metaphor might help. Or not. Either way, do not ever try to draw logical conclusions based on a metaphor.
double ***x;
what does it mean to declare declare a variable with three asterisks? Is this a pointer to a pointer to a pointer to a double?
It is a pointer to a pointer to a pointer to a double.
For syntax questions such as this try cdecl, having it bookmarked saved me some time with pointers to functions that return a const int * const T, note that it uses C, though it recognizes things like references giving a warning.
Indeed it is a pointer to a pointer to a pointer to a double.
Either a big multi-dimensional array, or just many levels of pointer indirection.
Say I want to cast A* to char* and vice-versa, we have two choices (I mean, many of us think we've two choices, because both seems to work! Hence the confusion!):
struct A
{
int age;
char name[128];
};
A a;
char *buffer = static_cast<char*>(static_cast<void*>(&a)); //choice 1
char *buffer = reinterpret_cast<char*>(&a); //choice 2
Both work fine.
//convert back
A *pA = static_cast<A*>(static_cast<void*>(buffer)); //choice 1
A *pA = reinterpret_cast<A*>(buffer); //choice 2
Even this works fine!
So why do we have reinterpret_cast in C++ when two chained static_cast can do its job?
Some of you might think this topic is a duplicate of the previous topics such as listed at the bottom of this post, but it's not. Those topics discuss only theoretically, but none of them gives even a single example demonstrating why reintepret_cast is really needed, and two static_cast would surely fail. I agree, one static_cast would fail. But how about two?
If the syntax of two chained static_cast looks cumbersome, then we can write a function template to make it more programmer-friendly:
template<class To, class From>
To any_cast(From v)
{
return static_cast<To>(static_cast<void*>(v));
}
And then we can use this, as:
char *buffer = any_cast<char*>(&a); //choice 1
char *buffer = reinterpret_cast<char*>(&a); //choice 2
//convert back
A *pA = any_cast<A*>(buffer); //choice 1
A *pA = reinterpret_cast<A*>(buffer); //choice 2
Also, see this situation where any_cast can be useful: Proper casting for fstream read and write member functions.
So my question basically is,
Why do we have reinterpret_cast in C++?
Please show me even a single example where two chained static_cast would surely fail to do the same job?
Which cast to use; static_cast or reinterpret_cast?
Cast from Void* to TYPE* : static_cast or reinterpret_cast
There are things that reinterpret_cast can do that no sequence of static_casts can do (all from C++03 5.2.10):
A pointer can be explicitly converted to any integral type large enough to hold it.
A value of integral type or enumeration type can be explicitly converted to a pointer.
A pointer to a function can be explicitly converted to a pointer to a function of a different type.
An rvalue of type "pointer to member of X of type T1" can be explicitly converted to an rvalue of type "pointer to member of Y of type T2" if T1 and T2 are both function types or both object types.
Also, from C++03 9.2/17:
A pointer to a POD-struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa.
You need reinterpret_cast to get a pointer with a hardcoded address (like here):
int* pointer = reinterpret_cast<int*>( 0x1234 );
you might want to have such code to get to some memory-mapped device input-output port.
A concrete example:
char a[4] = "Hi\n";
char* p = &a;
f(reinterpret_cast<char (&)[4]>(p)); // call f after restoring full type
// ^-- any_cast<> can't do this...
// e.g. given...
template <typename T, int N> // <=--- can match this function
void f(T (&)[N]) { std::cout << "array size " << N << '\n'; }
Other than the practical reasons that others have given where there is a difference in what they can do it's a good thing to have because its doing a different job.
static_cast is saying please convert data of type X to Y.
reinterpret_cast is saying please interpret the data in X as a Y.
It may well be that the underlying operations are the same, and that either would work in many cases. But there is a conceptual difference between saying please convert X into a Y, and saying "yes I know this data is declared as a X but please use it as if it was really a Y".
As far as I can tell your choice 1 (two chained static_cast) is dreaded undefined behaviour. Static cast only guarantees that casting pointer to void * and then back to original pointer works in a way that the resulting pointer from these to conversions still points to the original object. All other conversions are UB. For pointers to objects (instances of the user defined classes) static_cast may alter the pointer value.
For the reinterpret_cast - it only alters the type of the pointer and as far as I know - it never touches the pointer value.
So technically speaking the two choices are not equivalent.
EDIT: For the reference, static_cast is described in section 5.2.9 of current C++0x draft (sorry, don't have C++03 standard, the draft I consider current is n3225.pdf). It describes all allowed conversions, and I guess anything not specifically listed = UB. So it can blow you PC if it chooses to do so.
Using of C Style casting is not safer. It never checks for different types can be mixed together.
C++ casts helps you to make sure the type casts are done as per related objects (based on the cast you use). This is the more recommended way to use casts than using the traditional C Style casts that's always harmful.
Look, people, you don't really need reinterpret_cast, static_cast, or even the other two C++ styles casts (dynamic* and const).
Using a C style cast is both shorter and allows you to do everything the four C++-style cast let you do.
anyType someVar = (anyOtherType)otherVar;
So why use the C++-style casts? Readability. Secondly: because the more restrictive casts allow more code safety.
*okay, you might need dynamic