Discussion:
dynamic cast from void*
(too old to reply)
p***@gmail.com
2008-05-22 21:38:13 UTC
Permalink
Hi,

Just checking and I can guess the answer, but what if I have an array
of void*. Into which I put a variety of typed pointer objects.
Normally, when I get out the object, I already know what type it is so
I can static_cast and am safe because it was exactly that same type
when I put it in.

But how powerful and safe is a dynamic_cast in this case. In some
exception handling code, I won't know the original type that I put
in. Can I dynamic_cast from the void* array element to a particular
fully derived type to see if it is that type?

My guess is no, that's not safe and can cause a crash since the
objects are completely hetergenous.

Andy
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Mathias Gaunard
2008-05-23 02:41:01 UTC
Permalink
Post by p***@gmail.com
Just checking and I can guess the answer, but what if I have an array
of void*. [...]
But how powerful and safe is a dynamic_cast in this case.
dynamic_cast only works with objects which are of a polymorphic type.
Indeed, usually the pointer to the vtable is what is used to identify
the type.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
ManicQin
2008-05-24 15:27:45 UTC
Permalink
Post by Mathias Gaunard
Post by p***@gmail.com
Just checking and I can guess the answer, but what if I have an array
of void*. [...]
But how powerful and safe is a dynamic_cast in this case.
dynamic_cast only works with objects which are of a polymorphic type.
Indeed, usually the pointer to the vtable is what is used to identify
the type.
How can dynamic_cast identify whether the classes are polymorphic or
not?
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Alberto Ganesh Barbati
2008-05-25 15:44:46 UTC
Permalink
Post by ManicQin
How can dynamic_cast identify whether the classes are polymorphic or
not?
dynamic_cast does not try identify whether the classes are polymorphic
or not. The check is done statically at compile time by the compiler
itself. Each time you write dynamic_cast<whatever>(expr), the compiler
knows the *static* type of expr. If the type is T*, the compiler just
knows whether T is polymorphic or not! That's precisely why T is
*required* to be a complete class type.

HTH,

Ganesh
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
ManicQin
2008-05-26 21:47:28 UTC
Permalink
Post by Alberto Ganesh Barbati
dynamic_cast does not try identify whether the classes are polymorphic
or not. The check is done statically at compile time by the compiler
itself. Each time you write dynamic_cast<whatever>(expr), the compiler
knows the *static* type of expr. If the type is T*, the compiler just
knows whether T is polymorphic or not! That's precisely why T is
*required* to be a complete class type.
Thanks Ganesh,
Maybe I haven't explained my question properly but you answered my
question.
It even clarifies the reason why it has problems casting *void.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Mathias Gaunard
2008-05-25 15:44:48 UTC
Permalink
Post by ManicQin
How can dynamic_cast identify whether the classes are polymorphic or
not?
Because the pointer has a type.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Jens Müller
2008-05-25 15:57:35 UTC
Permalink
Post by ManicQin
Post by Mathias Gaunard
Post by p***@gmail.com
Just checking and I can guess the answer, but what if I have an array
of void*. [...]
But how powerful and safe is a dynamic_cast in this case.
dynamic_cast only works with objects which are of a polymorphic type.
Indeed, usually the pointer to the vtable is what is used to identify
the type.
How can dynamic_cast identify whether the classes are polymorphic or
not?
Why should it do that? It does not _work_ with the other kind.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
peter koch larsen
2008-05-23 02:40:45 UTC
Permalink
Post by p***@gmail.com
Hi,
Just checking and I can guess the answer, but what if I have an array
of void*. Into which I put a variety of typed pointer objects.
Normally, when I get out the object, I already know what type it is so
I can static_cast and am safe because it was exactly that same type
when I put it in.
But how powerful and safe is a dynamic_cast in this case. In some
exception handling code, I won't know the original type that I put
in. Can I dynamic_cast from the void* array element to a particular
fully derived type to see if it is that type?
My guess is no, that's not safe and can cause a crash since the
objects are completely hetergenous.
So far as I can interpret the standard, when the value is of type
void*, the result will always be 0, so your dynamic_cast is non-
sensical. The relevant paragraph is [expr.dynamic.cast] - 5.2.7 in my
edition of a C++ draft.

/Peter
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Greg Herlihy
2008-05-23 17:58:49 UTC
Permalink
Post by peter koch larsen
Post by p***@gmail.com
Just checking and I can guess the answer, but what if I have an array
of void*. Into which I put a variety of typed pointer objects.
Normally, when I get out the object, I already know what type it is so
I can static_cast and am safe because it was exactly that same type
when I put it in.
But how powerful and safe is a dynamic_cast in this case. In some
exception handling code, I won't know the original type that I put
in. Can I dynamic_cast from the void* array element to a particular
fully derived type to see if it is that type?
So far as I can interpret the standard, when the value is of type
void*, the result will always be 0, so your dynamic_cast is non-
sensical. The relevant paragraph is [expr.dynamic.cast] - 5.2.7 in my
edition of a C++ draft.
The pointers in this case are pointers to class objects and only
happen to have been cast to void pointers. So the question is, can
dynamic_cast<> recover the class pointer types from these void
pointers?

According to §5.2.7 answer is "yes" - but with two conditions: the
target class of the conversion must be polymorphic (that is, it must
have at least one virtual function) and the pointer being converted
(if not null) must point to an object of a polymorphic type (it does
not matter which polymorphic type). So in this case, as long as each
void pointer in the container points to an object of a polymorphic
class, than using dynamic_cast<> to convert the void pointers to class
pointers will work correctly. In particular, there is no requirement
that the polymorphic types of the class objects in the container must
be related to one another.

Greg
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Alberto Ganesh Barbati
2008-05-23 23:00:17 UTC
Permalink
Post by Greg Herlihy
The pointers in this case are pointers to class objects and only
happen to have been cast to void pointers. So the question is, can
dynamic_cast<> recover the class pointer types from these void
pointers?
According to §5.2.7 answer is "yes" - but with two conditions: the
target class of the conversion must be polymorphic (that is, it must
have at least one virtual function) and the pointer being converted
(if not null) must point to an object of a polymorphic type (it does
not matter which polymorphic type). So in this case, as long as each
void pointer in the container points to an object of a polymorphic
class, than using dynamic_cast<> to convert the void pointers to class
pointers will work correctly. In particular, there is no requirement
that the polymorphic types of the class objects in the container must
be related to one another.
You should read 5.2.7 again more thoroughly. There are two big mistakes
in your statement:

1) the target type need *not* be polymorphic. Consider this case:

struct NonPoly {};
struct Poly { virtual ~Poly() {}; }
struct Derived : Poly, NonPoly {};

void f(Poly* p)
{
NonPoly* q = dynamic_cast<NonPoly*>(p); // legal!
}

2) except for the special case described in paragraph 5, the static type
of the source pointer must be of T* with T a complete polymorphic type.
If the source pointer is of type void*, the code is ill-formed, period.
The check is done statically at compile time and it doesn't matter where
the pointer actually points to at runtime.

So the cast will *not* work correctly as you suggest. It will not work
at all.

HTH,

Ganesh
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Tony Delroy
2008-05-23 17:58:50 UTC
Permalink
Post by peter koch larsen
Post by p***@gmail.com
Just checking and I can guess the answer, but what if I have an array
of void*. Into which I put a variety of typed pointer objects.
Normally, when I get out the object, I already know what type it is so
I can static_cast and am safe because it was exactly that same type
when I put it in.
But how powerful and safe is a dynamic_cast in this case. In some
exception handling code, I won't know the original type that I put
in. Can I dynamic_cast from the void* array element to a particular
fully derived type to see if it is that type?
My guess is no, that's not safe and can cause a crash since the
objects are completely hetergenous.
So far as I can interpret the standard, when the value is of type
void*, the result will always be 0, so your dynamic_cast is non-
sensical. The relevant paragraph is [expr.dynamic.cast] - 5.2.7 in my
edition of a C++ draft.
Also looking at that part of the draft standard, I don't see the
behaviour you describe. Actually, 5.2.7.2 says:

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

which shows you can't cast a void* at all.

As also mentioned by Mathias, the classes have to be polymorphic (have
virtual functions).

If the void*s are to heterogeneous objects (as mentioned above) -
meaning they are not known to have a common base class - then you
can't rely on dynamic_cast<>. Note that even if they have a common
base class, you'd have to be very careful to extract a pointer to that
particular base, which is not necessarily at the same address as the
derived object.

BUT - and I expect to get caned for even suggesting this hack - you
may be able to use typeid comparison. The relevant part of the draft
standard:

2 When typeid is applied to an lvalue expression whose type is a
poly-
morphic class type (_class.virtual_), the result refers to a
type_info
object representing the type of the most derived
object
(_intro.object_) (that is, the dynamic type) to which the
lvalue
refers. If the lvalue expression is obtained by applying the unary
*
operator to a pointer8) and the pointer is a null pointer
value
(_conv.ptr_), the typeid expression throws the bad_typeid
exception
(_lib.bad.typeid_).

That is, if you have
class X { virtual void f(); };
void* p; // known to be polymorphic

You can try...
typeid(*(X*)p)
...to get the typeinfo. You can then compare typeinfo against the
type you'd like to try dynamic casting to.

Is this legal? It doesn't exactly say "no" above, though it's just
plain wrong from an intuitive perspective. FWIW (and I'm sure plenty
of people will say that's nothing), it seems to work fine in my
cursory g++/Linux testing.

Cheers,
Tony
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Alberto Ganesh Barbati
2008-05-23 23:00:32 UTC
Permalink
Post by Tony Delroy
That is, if you have
class X { virtual void f(); };
void* p; // known to be polymorphic
You can try...
typeid(*(X*)p)
...to get the typeinfo. You can then compare typeinfo against the
type you'd like to try dynamic casting to.
Unless the dynamic type of the object at p happens to be exactly X, this
code has undefined behaviour.

HTH,

Ganesh
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Frank Birbacher
2008-05-24 15:27:47 UTC
Permalink
Hi!
Post by Alberto Ganesh Barbati
Unless the dynamic type of the object at p happens to be exactly X, this
code has undefined behaviour.
Well, as I remember, void* need to be casted to and from the same type.

struct A {};
struct B : A {};

B bObject;
void* const voidToB = &bObject; //ok, cast from B*
B* const ptrToB = (B*)voidToB; //ok
A* const ptrToA = (A*)voidToB; //undefined

In an inheritance the addresses/pointers to the various subobjects don't
need to be numerically identical (which however is often the case). So I
think a function like

void foo(void* const p)
{ typeid( * (X*) p ); }

IS REALLY BROKEN, but it may work in some cases.

Anyway: it only works for all void* which were created from a pointer
with a static type of "X*" regardless the actual dynamic type, e.g. a
further derived class.

Regards,
Frank
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Alberto Ganesh Barbati
2008-05-23 17:57:34 UTC
Permalink
Post by peter koch larsen
Post by p***@gmail.com
Hi,
Just checking and I can guess the answer, but what if I have an array
of void*. Into which I put a variety of typed pointer objects.
Normally, when I get out the object, I already know what type it is so
I can static_cast and am safe because it was exactly that same type
when I put it in.
But how powerful and safe is a dynamic_cast in this case. In some
exception handling code, I won't know the original type that I put
in. Can I dynamic_cast from the void* array element to a particular
fully derived type to see if it is that type?
My guess is no, that's not safe and can cause a crash since the
objects are completely hetergenous.
So far as I can interpret the standard, when the value is of type
void*, the result will always be 0, so your dynamic_cast is non-
sensical. The relevant paragraph is [expr.dynamic.cast] - 5.2.7 in my
edition of a C++ draft.
Your interpretation is wrong. 5.2.7/2 requires that "If T is a pointer
type, v shall be an rvalue of a pointer to complete class type". This
requirement is not satisfied if v has type void* because void "is an
incomplete type that cannot be completed" (3.9.1/9). So a program
attempting to apply dynamic_cast<> on a void* is ill-formed.

HTH,

Ganesh
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Martin T
2008-05-26 22:22:10 UTC
Permalink
Post by p***@gmail.com
Hi,
Just checking and I can guess the answer, but what if I have an array
of void*. Into which I put a variety of typed pointer objects.
Normally, when I get out the object, I already know what type it is so
I can static_cast and am safe because it was exactly that same type
when I put it in.
But how powerful and safe is a dynamic_cast in this case. In some
exception handling code, I won't know the original type that I put
in. Can I dynamic_cast from the void* array element to a particular
fully derived type to see if it is that type?
My guess is no, that's not safe and can cause a crash since the
objects are completely hetergenous.
I am slightly confused why the other replies do not point out the simple
answer that it will not crash because you cannot cast from a
non-polymorphic type using dynamic_cast. The compiler will not accept
it. (Both MSVC++ and g++ on my Windows box here will issue an error for
this ....)

V* pv1 = new V();
void* pp = pv;
V* pv2 = dynamic_cast<V*>(pp);
v1.cpp(23) : error C2681: 'void *' : invalid expression type for
dynamic_cast


br,
Martin
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Alberto Ganesh Barbati
2008-05-27 22:56:41 UTC
Permalink
Post by Martin T
I am slightly confused why the other replies do not point out the simple
answer that it will not crash because you cannot cast from a
non-polymorphic type using dynamic_cast. The compiler will not accept
it. (Both MSVC++ and g++ on my Windows box here will issue an error for
this ....)
I don't know what other replies you may have read, but I said that
clearly in two of my replies. Also Tony Delroy's reply contained such
information.

Ganesh
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Continue reading on narkive:
Loading...