Is there a faster way to determine the type of an object at runtime than using dynamic_cast?

I have a type hierarchy - GenericClass and a number of derived classes, including InterestingDerivedClass, GenericClass - polymorphic. There interface

interface ICallback { virtual void DoStuff( GenericClass* ) = 0; }; 

which I need to implement. Then I want to determine the case where the GenericClass * pointer passed to ICallback :: DoStuff () is really a pointer to InterestingDerivedClass:

 class CallbackImpl : public ICallback { void DoStuff( GenericClass* param ) { if( dynamic_cast<InterestingDerivedClass*>( param ) != 0 ) { return; //nothing to do here } //do generic stuff } } 

GenericClass and derived classes are out of my control, I only manage CallbackImpl.

I timed the dynamic_cast operator - it takes about 1400 cycles, which is acceptable at the moment, but does not look very fast. I tried to read a breakdown of what was done during dynamic_cast in the debugger, and saw that it took a lot of instructions.

Since I really don't need a pointer to a derived class, is there a faster way to determine the type of an object at runtime using only RTTI? Maybe some specific implementation method that checks only the "is" relationship, but does not extract the pointer?

+6
c ++ polymorphism dynamic visual-c ++
source share
8 answers

I always look at using dynamic_cast as a code smell. You can replace it under any circumstances with polymorphic behavior and improve the quality of the code. In your example, I would do something like this:

 class GenericClass { virtual void DoStuff() { // do interesting stuff here } }; class InterestingDerivedClass : public GenericClass { void DoStuff() { // do nothing } }; class CallbackImpl : public ICallback { void DoStuff( GenericClass* param ) { param->DoStuff(); } } 

In your case, you cannot change the target classes; you are programming for a contract implied by a declaration of the GenericClass type. Therefore, it is hardly possible that something you can do is be faster than dynamic_cast will be, since everything else will require changing the client code.

+12
source share

As others have said, using a virtual function is good practice. There is another reason for using it that is not applicable in your case, since you cannot add VF, but it’s worth mentioning that I think it can be much faster than using dynamic translation. In some (not very strict) tests that I performed with g ++, the virtual function performed dynamic_cast 4 times.

Since there is such a mismatch, it might be worth creating your own inheritance hierarchy that wraps code that you do not control. You must create shell instances using dynamic_cast (once) to decide which derived type to create, and then use the virtual functions from there.

+5
source share

Looks like a beautiful hacker design for me. (As others have noted, using dynamic_cast usually a sign that you have a design issue.). But if most of the code is beyond your control, you are unlikely to be able to do this, I suppose.

But no, the only general solution that I know of is dynamic_cast . typeid matches only the most derived type, which may work in your case.

On the one hand, the reason dynamic_cast so expensive may be that it must go through the entire hierarchy of classes. If you have a deep hierarchy, this gets expensive (in other words, you don't have a deep hierarchy, in general, but especially in C ++).

(Of course, the first time you roll, most class description descriptions are likely to be skipped by cache, which may have distorted your benchmarking and made it more expensive than it is)

+2
source share

Will type_info comparison type_info faster? (call typeid on param parameter)

+1
source share

First of all, do not optimize prematurely. Secondly, if you are requesting an object for a specific implementation inside, it is likely that something is wrong with your design (think about double submitting).

As for the original question, introducing the GetRuntimeType() function in ICallback will be very enjoyable: see MFC for how to do this.

+1
source share

In your specific use case, the answer is to use virtual functions.

However, there are situations where you need to dynamically compress. There are several ways to make this operation faster (or much faster, depending on how smart your compiler implements dynamic_cast ), in particular if you limit yourself to a single inheritance. The basic idea is that if you somehow know the exact type, static_cast is much faster:

 f(A* pA) { if (isInstanceOfB(pA)) { B* pB = static_cast<B*>(pA); // do B stuff... } } 

Of course, now the problem is the quick implementation of isInstanceOfB ().

See boost :: type_traits , for example.

+1
source share

The standard dynamic_cast is very flexible, but usually very slow, since it handles many cases of angles that you probably are not interested in. If you use single inheritance, you can replace it with a simple implementation based on virtual functions.

Implementation Example:

 // fast dynamic cast //! Fast dynamic cast declaration /*! Place USE_CASTING to class that should be recnognized by dynamic casting. Do not forget do use DEFINE_CASTING near class definition. *\note Function dyn_cast is fast and robust when used correctly. Each class that should be used as target for dyn_cast must use USE_CASTING and DEFINE_CASTING macros.\n Forgetting to do so may lead to incorrect program execution, because class may be sharing _classId with its parent and IsClassId will return true for both parent and derived class, making impossible' to distinguish between them. */ #define USE_CASTING(baseType) \ public: \ static int _classId; \ virtual size_t dyn_sizeof() const {return sizeof(*this);} \ bool IsClassId( const int *t ) const \ { \ if( &_classId==t ) return true; \ return baseType::IsClassId(t); \ } //! Fast dynamic cast root declaration /*! Place USE_CASTING_ROOT to class that should act as root of dynamic casting hierarchy */ #define USE_CASTING_ROOT \ public: \ static int _classId; \ virtual size_t dyn_sizeof() const {return sizeof(*this);} \ virtual bool IsClassId( const int *t ) const { return ( &_classId==t ); } //! Fast dynamic cast definition #define DEFINE_CASTING(Type) \ int Type::_classId; template <class To,class From> To *dyn_cast( From *from ) { if( !from ) return NULL; if( from->IsClassId(&To::_classId) ) { assert(dynamic_cast<To *>(from)); return static_cast<To *>(from); } return NULL; } 

However, I agree with others. dynamic_cast is suspicious, and you will most often be able to achieve the same goal in a much cleaner way. However, it seems that there may be some cases where it can be really useful and readable.

One more note: if you say that the classes in question are beyond your control, this solution will not help you, since you need to change the classes (not so many, just add a few lines, but you need to change them). If this is true, then you need to use what the language offers, i.e. dynamic_cast and typeinfo.

+1
source share
0
source share

All Articles