dynamic_cast expensive?

C

cppquester

When I replaced the dynamic cast in the code excerpt below
(here each class knows it type), I gained a speedup of about factor
4(!)
(in release mode (-O2))

Why is a dynamic cast so expensive? I thought basically the RTTI
system basically does
what I did (store the type (implicitely) and then cast or return
NULL).

Or might this be specific to my platform (g++ 4.2.4)?

Thanks,
Marc


thisType* lEnd=dynamic_cast<thisType*>(derived);
if( lEnd == NULL)
throw MyException("Type changed.");*/


if( derived->Type() != this->type)
throw MyException("Type changed.");
thisType* lEnd=static_cast<thisType*>(derived);
 
M

Martijn van Buul

* cppquester:
When I replaced the dynamic cast in the code excerpt below
(here each class knows it type), I gained a speedup of about factor
4(!)
(in release mode (-O2))

Why is a dynamic cast so expensive? I thought basically the RTTI
system basically does
what I did (store the type (implicitely) and then cast or return
NULL).

No, that's not what it does. Your alternative code suggests that you
think that a dynamic_cast<T> will fail if the supplied pointer is not
pointing at an instance of type T. It's slightly more complex than
that.

Consider the following example:

class object { ... };

class rectangle : public object { ... };

class square : public rectangle { ... };

square mySquare;
object* squarePtr = &mySquare;

Both the dynamic cast and your approach will work for a cast to square*.
However, yours will *fail* for a cast to rectangle*, whereas the
dynamic_cast<> will work. Things get increasingly complex if you take
multiple inheritance into consideration. Either way, dynamic_cast<> may have
to traverse the entire inheritance tree in order to determine success or
failure, and this may indeed turn out to be expensive - especially if you
have a significant amount of classes derived from a common base class.

Bottom line: Your Type() based approach will only work for *exact* matches,
not for casts to an intermediate base class.
Or might this be specific to my platform (g++ 4.2.4)?
No.

thisType* lEnd=dynamic_cast<thisType*>(derived);
if( lEnd == NULL)
throw MyException("Type changed.");*/

This also means that the above test is possibly flawed. It wouldn't
generate an exception in case 'derived' points to an object that is
-derived- from thisType (but not a thisType itself). Your choice of
variable names is slightly confusing, so I'm not really sure that's
what you want.
if( derived->Type() != this->type)
throw MyException("Type changed.");
thisType* lEnd=static_cast<thisType*>(derived);

You coud use a typeid() keyword for a more standard approach; something
along the line of

if (std::typeid(derived) != std::typeid(type))
...

Note that there's a performance issue lurking here too; while
std::typeid() is constant order (as opposed to dynamic_cast<>), comparing
the std::type_info resulting from the calls to std::typeid() may be
expensive. While it is implementation-defined, it'll most likely contain
the typename as a (not necessarily human-readable) string, which makes
comparison not cheap either.

There are a few workarounds floating around, using pointers to
std::type_info instead, but that smells like undefined behaviour. I know
from own experience that this trick will most likely not work for libraries.
 
S

Salt_Peter

When I replaced the dynamic cast in the code excerpt below
(here each class knows it type), I gained a speedup of about factor
4(!)
(in release mode (-O2))

Why is a dynamic cast so expensive? I thought basically the RTTI
system basically does
what I did (store the type (implicitely) and then cast or return
NULL).

Or might this be specific to my platform (g++ 4.2.4)?

Thanks,
Marc

  thisType* lEnd=dynamic_cast<thisType*>(derived);
  if( lEnd == NULL)
    throw MyException("Type changed.");*/

  if( derived->Type() != this->type)
    throw MyException("Type changed.");
  thisType* lEnd=static_cast<thisType*>(derived);

Not enough info.
A class always knows its type, you don't need RTTI for that. In the
case where the object 'derived' above is of a type which is a
derivative of thisType, then derived will always be of type thisType.
So doing a dynamic cast is pointless, doing any cast is pointless.

So to answer your question: the question is irrelevant.

Btw, C++ programmers are reknown to be pathetic when it comes to
guessing. Try making a simple, short compileable example to explain
what you seek.

class thisType { };
class Derived : public thisType { };

int main()
{
// do stuff
}
 
C

cppquester

Not enough info.
A class always knows its type, you don't need RTTI for that. In the
case where the object 'derived' above is of a type which is a
derivative of thisType, then derived will always be of type thisType.
So doing a dynamic cast is pointless, doing any cast is pointless.

So to answer your question: the question is irrelevant.

Btw, C++ programmers are reknown to be pathetic when it comes to
guessing. Try making a simple, short compileable example to explain
what you seek.

class thisType { };
class Derived : public thisType { };

int main()
{
  // do stuff

}


You are right, it was not clear.
Actually the following was meant:

class Base { virtual int Type(); ...};

class thisType: public Base { int t; int Type(){ return t;} ...};
class Derived : public Base { int t; int Type(){ return t;} ...};
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top