views:

336

answers:

8

I need to convert an integral type which contains an address to the actual pointer type. I could use reinterpret_cast as follows:

MyClass *mc1 = reinterpret_cast<MyClass*>(the_integer);

However, this does not perform any run-time checks to see if the address in question actually holds a MyClass object. I want to know if there is any benefit in first converting to a void* (using reinterpret_cast) and then using dynamic_cast on the result. Like this:

void *p = reinterpret_cast<void*>(the_integer);
MyClass *mc1 = dynamic_cast<MyClass*>(p);
assert(mc1 != NULL);

Is there any advantage in using the second method?

+2  A: 

No, there's no specific advantage in doing so. The moment you use reinterpret_cast, all bets are off. It's up to you to be sure the cast is valid.

Mehrdad Afshari
+1  A: 

Actually no serious advantage. If the void* points to something that is not a pointer to a polymorphic object you run into undefined behaviour (usually an access violation) immediately.

sharptooth
Except when you don't. Relying on undefined behavior is never a smart idea.
Roger Pate
+1  A: 

The safe way is to keep a record of all live MyClass objects. It's best to keep this record in a std::set<void*>, which means you can easily add, remove and test elements.

The reason for storing them as void*s is that you don't risk nastyness like creating unaligned MyClass* pointers from your integers.

MSalters
+3  A: 

Type checking on dynamic_cast is implemented in different ways by different C++ implementations; if you want an answer for your specific implementation you should mention what implementation you are using. The only way to answer the question in general is to refer to ISO standard C++.

By my reading of the standard, calling dynamic_cast on a void pointer is illegal:

dynamic_cast<T>(v)

"If T is a pointer type, v shall be an rvalue of a pointer to complete class type"

(from 5.2.7.2 of the ISO C++ standard). void is not a complete class type, so the expression is illegal.

Interestingly, the type being cast to is allowed to be a void pointer, i.e.

void * foo = dynamic_cast<void *>(some_pointer);

In this case, the dynamic_cast always succeeds, and the resultant value is a pointer to the most-derived object pointed to by v.

Tim
This is because after `void* foo = dynamic_cast<void*>(some_pointer);`, you may find `foo != some_pointer` (which means some\_pointer was pointing at a base subobject).
Roger Pate
A: 
  • First of all "reinterpreting" int to void * is a bad idea. If sizeof(int) is 4 and sizeof(void *) is 8 (64x system) it is ill-formed.

  • Moreover dynamic_cast is valid only for the case of the polymorphic classes.

Alexey Malistov
+1  A: 

If you know for sure that the_integer points to a known base class (that has at least one virtual member), there might in fact be an advantage: knowing that the object is of a specific derived class. But you’d have to reinterpret_cast to your base class first and then do the dynamic_cast:

BaseClass* obj = reinterpret_cast<BaseClass*>(the_integer);
MyClass* myObj = dynamic_cast<BaseClass*>(obj);

Using a void* in dynamic_cast is useless and simply wrong. You cannot use dynamic_cast to check if there’s a valid object at some arbitrary location in memory.

You should also pay attention when storing addresses in non-pointer type variables. There are architectures where sizeof(void*) != sizeof(int), e.g. LP64.

Nikolai Ruhe
A: 

Option 1 is your only (semi) portable/valid option.

Option 2: is not valid C++ as the dynamic_cast (as void is not allowed).

At an implementation level it requires type information from the source type to get to the destination type. There is no way (or there may be no way) to get the runtime source type information from a void* so this is not valid either.

Dynamic_Cast is used to cas up and down the type hierarchy not from unknown types.

As a side note you should probably be using void* rather than an integer to store an untyped pointer. There is potential for an int not to be large enough to store a pointer.

Martin York
A: 

The safest way to handle pointers in C++ is to handle them typesafe. This means:

  • Never store pointers in anything else than a pointer
  • Avoid void pointers
  • Never pass pointers to other processes
  • consider weak_ptr if you plan to use pointers over threads

The reason for this is: what you are planning to do is unsafe and can be avoided unless you're interfacing with unsafe (legacy?) code. In this case consider MSalters' answer, but be aware that it still is a hassle.

stefaanv