Casting to Void* and Back to Original_Data_Type*

Casting to void* and Back to Original_Data_Type*

What I wonder is if there are any pitfalls/ issues of doing this?

You need to be absolutely sure while casting the the void* back to the particular type, if you don't, you end up with an Undefined behavior and a potential disaster. Once you use void * you lose type safety.It is difficult to keep track of what type a void * is actually pointing to, there is no way to guarantee or determine that it indeed points to the type to which you are going to typecast it back to.

Is there any way that we could run in to an error or undefined condition when we are casting to void* and back again?

Yes, the scenario mentioned in #1.

How should we resolve such issues if there are any?

Avoid using void * in C++ completely, instead use templates and inheritance.

In C you might absoultely need it in certain situations but try to keep its use to a minimum.

Bottomline,

C/C++ allows you to shoot yourself in foot, it is up to you to do or not do so.

Casting to void* and typedefs in C++

It shouldn't cause any trouble, but it will only give API users a false sense of security (as any arbitrary pointer will also work). There's nothing to prevent the compiler from complaining if you do something like:

int i;
// ....
modifyIndex(&i);

So while you won't have any problems, you won't have any compile-time checks and enforcements either.

Do note that you have the choice of simply declaring the class without actually defining it.

The proper way to solve the void-pointer "problem" (and it's not really a problem, it's just an aspect of C (and thus C++) which may make code difficult to maintain without proper care/documentation) is to somehow expose Index as an opaque type; e.g.

// index.h
class Index;
// ...
void modifyIndex(Index *i);

Convert void* to a dynamic type

instead of

char* myType= typeid(i).name();//get the name of type of "i"
int p = *((myType*) pointer); // how to implement?

use

typedef decltype(i) myType;
myType p = *((myType*) pointer);

or better:

typedef decltype(i) myType;
auto p = *reinterpret_cast<myType*>(pointer);

Works with c++11 or later. If you want to decltype on older c++ compilers, it is emulated in boost.

Edit. This is probably different from what you wanted to do, which I suppose is something like this:

void myFunction(void* unknownParam) {
typedef (realTypeOf unknownParam) RealType; // <-- this is not real c++
RealType &a = *reinterpret_cast<RealType*>(unknownParam)
//do stuff using 'a'
}

This is not possible in C++, but there is a reason: it doesn't make much sense.
And the reason is that for myFunction to be valid the //do stuff using 'a' part should be valid for whatever type RealType ends up being. As such, it cannot rely on any feature the RealType type have: it cannot use any of its methods, it cannot use any operator, it cannot even know whether it is a class or not. Basically, you cannot do anything more with it than what you would already be able to do on a void*, so giving the type a name doesn't really help you much.

A language feature that is similar to what you want (but not quite it) is type reflection, which is not present in C++, but you can find it in language such as Java, Objective-C or C#. Basically, you ask the object itself if it has a certain method, and eventually call it. An example in Objective-C

-(void)myFunction:(id)unknownParam {
if([unknownParam respondsToSelector:@selector(myMethod)])
[unknownParam performSelector:@selector(myMethod)]
}

Is there a safe way to cast void* to class pointer in C++

Yes, static_cast is correct here.

Assuming that the void* value is only copied inside the C library, static_cast will return the original pointer value pointing to the passed object if you cast it to a pointer of the same type as it was originally.

Under some conditions you may also cast to a different type, the rules are those of reinterpret_cast (which simply casts via two static_casts with void* intermediate).

If you cast it to any type not allowed under those rules, e.g. an unrelated class type, trying to access the object through the pointer will cause undefined behavior. There is no way of detecting this mistake. You need to take care of doing it correctly yourself.

C++ Why wrong override method get called

You should just do this: void callBaseB(BaseB *p) {p->methodB(0);}.

If you want to keep void *p as a parameter, you need to cast it to exactly Child * first. Either:

BaseB *b = (Child *)p;
b->methodB(0);

Or:

Child *b = (Child *)p;
b->methodB(0);

Alternatively, cast to BaseB * before converting to void *. Then casting from void * back to Base * will work.


What happens here is that the BaseB subobject is at non-zero offset inside of Child.

When you convert Child * to BaseB * (either explicitly with a cast, or implicitly, either by assigning pointers or by calling a method of BaseB on the pointer), the compiler automatically offsets the pointer by the required amount, to point to the BaseB subobject.

The offset is determined entirely at compile-time (unless virtual inheritance is involved), based on the two types.

When you obscure the source type using void *, the compiler has no way to determine the correct offset, and doesn't even try to apply any offset, so you get weird behavior, because the resulting BaseB * doesn't point to a BaseB instance, but rather to some junk inside of Child.

Even with virtual inheritance, despite the offset being determined at runtime, the calculation depends on the source pointer type being known.

Type punning with void * without breaking the strict aliasing rule in C99

void * has nothing to do with type-punning. Its main purposes are:

  1. To allow for generic allocation and freeing operations that don't care about the type of the object the caller is storing there (e.g. malloc and free).

  2. To allow a caller to pass a pointer to an arbitrary type through a function that will pass it back via a callback, (e.g. qsort and pthread_create). In this case, the compiler cannot enforce type checking; it's your responsibility when writing the caller and callback to ensure that the callback accesses the object with the correct type.

Pointers to void are also used in a few places (like memcpy) that actually operate on an object as the overlaid unsigned char [] representation for the object. This could be seen as type-punning, but it's not an aliasing violation because char types are allowed to alias anything to access its representation. In this case, unsigned char * would also work, but void * has the advantage that pointers automatically convert to void *.

In your example, since the original type is int and not a union, there is no legal way to type-pun and access it as short. You could instead copy the value of x to a union, perform well-defined type-punning there, then copy it back. A good compiler should omit the copy entirely. Alternatively, you could break the write down into char writes and then it would be legal aliasing.



Related Topics



Leave a reply



Submit