Re: dynamic_cast expensive?
* 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.
--
Martijn van Buul - pino@dohd.org