Are there any practical uses for a dynamic cast for a void pointer?

In C ++, building T q = dynamic_cast<T>(p); debugs the runtime of pointer p to another type of pointer T , which must appear in the inheritance hierarchy of dynamic type *p for success. All is well and good.

However, it is also possible to execute dynamic_cast<void*>(p) , which simply returns a pointer to the "most derived object" (see 5.2.7 :: 7 in C ++ 11). I understand that this function is probably provided free of charge when implementing a dynamic cast, but is it useful in practice? After all, its return type is void* at best, so is that good?

+69
c ++ dynamic-cast
Nov 14 '11 at 3:22 a.m.
source share
7 answers

dynamic_cast<void*>() can indeed be used for authentication, even if it deals 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 
+68
Nov 14 '11 at 15:48
source share

Remember that C ++ allows you to do things in the old ways C.

Suppose I have some API in which I am forced to smuggle an object pointer through a void* type, but where does the callback that it ultimately passed 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)); } 

WRONG! the code is incorrect because it fails if there is multiple inheritance (and also work in the absence is not guaranteed).

Of course, the API is not very C ++ style, and even the "right" code may go wrong if I inherit from ActualType . So I would not argue that this is a brilliant use of dynamic_cast<void*> , but it is a use.

+7
Nov 14 '11 at 16:08
source share

Drop pointers prior to void* have their importance starting from C-days. The most suitable place is in the operating system's memory manager. It should store the entire pointer and object of what you are creating. By storing it in void *, they generalize it to store any object in the memory manager's data structure, which can be heap/B+Tree or a simple arraylist .

For simplicity, take an example of creating a list common elements (The list contains elements of completely different classes). This could only be used with void* .

standard says dynamic_cast should return null for odd type casting, and the standard also ensures that any pointer must be able to enter it into void * and back from it with the exception of only function pointers.

The practical use of the standard application layer is very small for void* typecasting, but it is widely used in low-level / embedded systems.

Usually you would like to use reinterpret_cast for low-level material, for example, in 8086 it is used to shift the pointer of the same base to get the address, but not limited to it.

Edit: The standard says that you can convert any pointer to void* even with dynamic_cast<> , but it doesn’t say where you can convert void* back to an object.

For most uses, this is a one-way street, but there are some unavoidable uses.

It just says that dynamic_cast<> needs type information in order to convert it back to the requested type.

There are many APIs that require you to pass void* to some object, for example. java / Jni Code passes an object as void* .
If you are pretty sure that the type you entered is correct , you can ask the compiler to make dynmaic_cast<> using a trick.

Take a 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 the case.

+4
Nov 16 '11 at 19:14
source share

useful when we put memory back into the memory pool, but we only store the pointer to the base class. In this case, we must find out the source address.

+1
Nov 20 '11 at 8:35
source share

Expanding on @BruceAdi's answer and inspired by this discussion , here is a polymorphic situation that may require pointer adjustment. Suppose we have this factory setting:

 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 clear this 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 reuse memory:

 void * addr = dynamic_cast<void*>(p); p->~Base(); p = InplaceFactory(addr, "some", "arguments"); delete p; // OK now 
+1
Aug 09 2018-12-12T00:
source share

This may be one way to provide Opaque Pointer via ABI. Opaque pointers - and, more generally, Opaque data types - are used to transfer objects and other resources between library code and client code in a way that client code can be isolated from library implementation details. There are other ways for this to be sure, and perhaps some of them would be better for a particular use case.

Windows uses Opaque Pointers a lot in its API. HANDLE , as it seems to me, is usually an opaque pointer to the actual resource, for example, for HANDLE . HANDLE may be the core. Objects, such as files, GDI objects, and all kinds of user-defined objects of different types - all this should be significantly different in implementation, but they will all be returned to the HANDLE 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"; } 
0
Nov 22 '11 at 18:11
source share

Don't do it 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.

0
Nov 23 2018-11-11T00:
source share



All Articles