Why is usage of the typeid keyword bad design?

xcrypt picture xcrypt · Mar 3, 2012 · Viewed 7.2k times · Source

I have heard a lot of people say any usage of typeid is bad design, yet to me it seems like it offers great utility.

  1. When (and why) is usage of typeid "bad design"?
  2. When is usage of typeid acceptable?
  3. When it is not acceptable, but you still need something alike, what would an alternative be that would have good design?

Answer

Nicol Bolas picture Nicol Bolas · Mar 3, 2012

The problem isn't with typeid. The problem is that seeing typeid would encourage you to write this:

PolymorphicType *pType = ...;
if(typeid(*pType) == typeid(Derived1))
  pType->Func1();
else if(typeid(*pType) == typeid(Derived2))
  pType->Func2();
else if(typeid(*pType) == typeid(Derived3))
  pType->Func3();

This is what we call "really stupid". This is a virtual function call done in about the least reasonable way possible. typeid has the potential for abuse when used to replace dynamic_cast and virtual functions.

This example may sound far-fetched. After all, it's obvious that this is just a virtual call. But bad code often grows from the path of least resistance; all it takes is for one person to do a typeid() == typeid(), and the seed of this code has begin. In general, if you're directly using typeid frequently, odds are very good that you're doing something that could be better done with other language constructs.

typeid is the polymorphic type deduction method of last resort.

Is all usage of typeid wrong? Of course not. boost::any wouldn't be possible without it. Well it would be possible, but it wouldn't be any safer than void*. typeid is what makes type-safe boost::any type erasure possible. There are other legitimate uses of it.

But in code-lines-to-use ratio, I would suggest it should be in about one in 10,000 lines of code, at most. Much fewer than that, and you're probably using it wrong.

Is type checking slow?

In general, the main reason to call typeid is either in templated code (as in boost::any) or when you're expecting a polymorphic type. If the type is statically determined (ie: a typename or value of a non-polymorphic type is given), then you can expect it to be done at compile-time.

It's polymorphic values you should be concerned about. I've seen a performance test that showed that some typeid implementations actually walk the class hierarchy, so the time it takes for them to find the type is proportional to the number of classes between the real type and the given type. Every implementation will be different, but that's a pretty good indication that maybe you shouldn't put it in performance-critical code.