Are there practical uses for dynamic-casting to void pointer?

C++Dynamic Cast

C++ Problem Overview


In C++, the T q = dynamic_cast<T>(p); construction performs a runtime cast of a pointer p to some other pointer type T that must appear in the inheritance hierarchy of the dynamic type of *p in order to succeed. That is all fine and well.

However, it is also possible to perform dynamic_cast<void*>(p), which will simply return a pointer to the "most derived object" (see 5.2.7::7 in C++11). I understand that this feature probably comes out for free in the implementation of the dynamic cast, but is it useful in practice? After all, its return type is at best void*, so what good is this?

C++ Solutions


Solution 1 - C++

The dynamic_cast<void*>() can indeed be used to check for identity, even if dealing with multiple inheritance.

Try this code:

#include <iostream>

class B {
public:
    virtual ~B() {}
};

class D1 : public B {
};

class D2 : public B {
};

class DD : public D1, public D2 {
};

namespace {
    bool eq(B* b1, B* b2) {
        return b1 == b2;
    }

    bool eqdc(B* b1, B *b2) {
        return dynamic_cast<void*>(b1) == dynamic_cast<void*>(b2);
    }
};

int
main() {
    DD *dd = new DD();
    D1 *d1 = dynamic_cast<D1*>(dd);
    D2 *d2 = dynamic_cast<D2*>(dd);

    std::cout << "eq: " << eq(d1, d2) << ", eqdc: " << eqdc(d1, d2) << "\n";
    return 0;
}

Output:

eq: 0, eqdc: 1

Solution 2 - C++

Bear in mind that C++ lets you do things the old C way.

Suppose I have some API in which I'm forced to smuggle an object pointer through the type void*, but where the callback it's eventually passed to will know its dynamic type:

struct BaseClass {
    typedef void(*callback_type)(void*);
    virtual callback_type get_callback(void) = 0;
    virtual ~BaseClass() {}
};

struct ActualType: BaseClass {
    callback_type get_callback(void) { return my_callback; }

    static void my_callback(void *p) {
        ActualType *self = static_cast<ActualType*>(p);
        ...
    }
};

void register_callback(BaseClass *p) {
   // service.register_listener(p->get_callback(), p); // WRONG!
   service.register_listener(p->get_callback(), dynamic_cast<void*>(p));
}

The WRONG! code is wrong because it fails in the presence of multiple inheritance (and isn't guaranteed to work in the absence, either).

Of course, the API isn't very C++-style, and even the "right" code can go wrong if I inherit from ActualType. So I wouldn't claim that this is a brilliant use of dynamic_cast<void*>, but it's a use.

Solution 3 - C++

Casting pointers to void* has its importance since way back in C days. Most suitable place is inside the memory manager of Operating System. It has to store all the pointer and the object of what you create. By storing it in void* they generalize it to store any object on to the memory manager data structure which could be heap/B+Tree or simple arraylist.

For simplicity take example of creating a list of generic items(List contains items of completely different classes). That would be possible only using void*.

standard says that dynamic_cast should return null for illegal type casting and standard also guarantees that any pointer should be able to type cast it to void* and back from it with only exception of function pointers.

Normal application level practical usage is very less for void* typecasting but it is used extensively in low level/embedded systems.

Normally you would want to use reinterpret_cast for low level stuff, like in 8086 it is used to offset pointer of same base to get the address but not restricted to this.

Edit: Standard says that you can convert any pointer to void* even with dynamic_cast<> but it no where states that you can not convert the void* back to the object.

For most usage, its a one way street but there are some unavoidable usage.

It just says that dynamic_cast<> needs type information for converting it back to the requested type.

There are many API's that require you to pass void* to some object eg. java/Jni Code passes the object as void*.
Without type info you cannot do the casting.If you are confident enough that type requested is correct you can ask compiler to do the dynmaic_cast<> with a trick.

Look at this code:

class Base_Class {public : virtual void dummy() { cout<<"Base\n";} };
class Derived_Class: public Base_Class { int a; public: void dummy() { cout<<"Derived\n";} };
class MostDerivedObject : public Derived_Class {int b; public: void dummy() { cout<<"Most\n";} };
class AnotherMostDerivedObject : public Derived_Class {int c; public: void dummy() { cout<<"AnotherMost\n";} };

int main () {
  try {
 	Base_Class * ptr_a = new Derived_Class;
 	Base_Class * ptr_b = new MostDerivedObject;
 	Derived_Class * ptr_c,*ptr_d;

    	ptr_c = dynamic_cast< Derived_Class *>(ptr_a);
    	ptr_d = dynamic_cast< Derived_Class *>(ptr_b);

		void* testDerived = dynamic_cast<void*>(ptr_c);
		void* testMost = dynamic_cast<void*>(ptr_d);
		Base_Class* tptrDerived = dynamic_cast<Derived_Class*>(static_cast<Base_Class*>(testDerived));
		tptrDerived->dummy();
		Base_Class* tptrMost = dynamic_cast<Derived_Class*>(static_cast<Base_Class*>(testMost));
		tptrMost->dummy();
		//tptrMost = dynamic_cast<AnotherMostDerivedObject*>(static_cast<Base_Class*>(testMost));
		//tptrMost->dummy(); //fails
		
  	} catch (exception& my_ex) {cout << "Exception: " << my_ex.what();}
	system("pause");
  return 0;
}

Please correct me if this is not correct in any way.

Solution 4 - C++

it is usefull when we put the storage back to memory pool but we only keep a pointer to the base class. This case we should figure out the original address.

Solution 5 - C++

Expanding on @BruceAdi's answer and inspired by this discussion, here's a polymorphic situation which may require pointer adjustment. Suppose we have this factory-type setup:

struct Base { virtual ~Base() = default; /* ... */ };
struct Derived : Base { /* ... */ };

template <typename ...Args>
Base * Factory(Args &&... args)
{
    return ::new Derived(std::forward<Args>(args)...);
}

template <typename ...Args>
Base * InplaceFactory(void * location, Args &&... args)
{
    return ::new (location) Derived(std::forward<Args>(args)...);
}

Now I could say:

Base * p = Factory();

But how would I clean this up manually? I need the actual memory address to call ::operator delete:

void * addr = dynamic_cast<void*>(p);

p->~Base();              // OK thanks to virtual destructor

// ::operator delete(p); // Error, wrong address!

::operator delete(addr); // OK

Or I could re-use the memory:

void * addr = dynamic_cast<void*>(p);
p->~Base();
p = InplaceFactory(addr, "some", "arguments");

delete p;  // OK now

Solution 6 - C++

This might be one way to provide an Opaque Pointer through an ABI. Opaque Pointers -- and, more generally, Opaque Data Types -- are used to pass objects and other resources around between library code and client code in such a way that the client code can be isolated from the implementation details of the library. There are other ways to accomplish this, to be sure, and maybe some of them would be better for a particular use case.

Windows makes a lot of use of Opaque Pointers in its API. HANDLE is, I believe, generally an opaque pointer to the actual resource you have a HANDLE to, for example. HANDLEs can be Kernel Objects like files, GDI objects, and all sorts of User Objects of various kinds -- all of which must be vastly different in implementation, but all are returned as a HANDLE to the user.

#include <iostream>
#include <string>
#include <iomanip>
using namespace std;


/*** LIBRARY.H ***/
namespace lib
{
	typedef void* MYHANDLE;

	void		ShowObject(MYHANDLE h);
	MYHANDLE	CreateObject();
	void		DestroyObject(MYHANDLE);
};

/*** CLIENT CODE ***/
int main()
{
	for( int i = 0; i < 25; ++i )
	{
		cout << "[" << setw(2) << i << "] :";
		lib::MYHANDLE h = lib::CreateObject();
		lib::ShowObject(h);
		lib::DestroyObject(h);
		cout << "\n";
	}
}

/*** LIBRARY.CPP ***/
namespace impl
{
	class Base { public: virtual ~Base() { cout << "[~Base]"; } };
	class Foo	: public Base { public: virtual ~Foo() { cout << "[~Foo]"; } };
	class Bar	: public Base { public: virtual ~Bar() { cout << "[~Bar]"; } };
};

lib::MYHANDLE lib::CreateObject()
{
	static bool init = false;
	if( !init )
	{
		srand((unsigned)time(0));
		init = true;
	}

	if( rand() % 2 )
		return static_cast<impl::Base*>(new impl::Foo);
	else
		return static_cast<impl::Base*>(new impl::Bar);
}

void lib::DestroyObject(lib::MYHANDLE h)
{
	delete static_cast<impl::Base*>(h);
}

void lib::ShowObject(lib::MYHANDLE h)
{
	impl::Foo* foo = dynamic_cast<impl::Foo*>(static_cast<impl::Base*>(h));
	impl::Bar* bar = dynamic_cast<impl::Bar*>(static_cast<impl::Base*>(h));

	if( foo ) 
		cout << "FOO";
	if( bar )
		cout << "BAR";
}

Solution 7 - C++

Don't do that at home

struct Base {
	virtual ~Base ();
};

struct D : Base {};

Base *create () {
	D *p = new D;
	return p;
}

void *destroy1 (Base *b) {
	void *p = dynamic_cast<void*> (b);
	b->~Base ();
	return p;
}

void destroy2 (void *p) {
	operator delete (p);
}

int i = (destroy2 (destroy1 (create ())), i);

Warning: This will not work if D is defined as:

struct D : Base {
void* operator new (size_t);
void operator delete (void*);
};

and there is no way to make it work.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKerrek SBView Question on Stackoverflow
Solution 1 - C++mitchnullView Answer on Stackoverflow
Solution 2 - C++Steve JessopView Answer on Stackoverflow
Solution 3 - C++PraveenView Answer on Stackoverflow
Solution 4 - C++BruceAdiView Answer on Stackoverflow
Solution 5 - C++Kerrek SBView Answer on Stackoverflow
Solution 6 - C++John DiblingView Answer on Stackoverflow
Solution 7 - C++curiousguyView Answer on Stackoverflow