10

... approximately compared to a typical std::string::operator==()? I give some more details below, I'm not sure if they are of any relevance. Answer with complexity or approximation is good enough. Thanks!

Details: I will use it inside a for loop over a list to find some specific instances. I estimate my average level of inheritance to 3.5 classes. The one I'm looking for has a parent class, a grandparent and above that two "interfaces", i.e. to abstract classes with a couple of virtual void abc() = 0;.

There is no sub-class to the one I'll be looking for.

Motti
  • 110,860
  • 49
  • 189
  • 262
Jonas Byström
  • 25,316
  • 23
  • 100
  • 147
  • 5
    -1 as stated, wanting a comparision between `dynamic_cast` and `std::string::operator==`, the question is meaningless. and if that sillyness is removed, then the answer to "how fast?" is just the single word "**measure**". – Cheers and hth. - Alf Mar 19 '12 at 21:25
  • 4
    @Alf, if the options the OP is facing is to perform `dynamic_cast` or compare a _type_ `string` (either `typeid.name` or a user written virtual function) the question _could_ make sense. – Motti Mar 19 '12 at 21:27
  • 1
    @Alf: the question is meaningful to me. Crashworks' measurements shows there is a significant difference, which I assume is pretty general. That saved me time (to code instead of measuring). Between complaining and being productive you picked the silly option. – Jonas Byström Mar 19 '12 at 22:20

2 Answers2

13

It depends hugely on your compiler, your particular class hierarchy, the hardware, all sorts of factors. You really need to measure it directly inside your particular application. You can use rdtsc or (on Windows) QueryPerformanceCounter to get a relatively high-precision timer for that purpose. Be sure to time loops or sleds of several thousand dynamic_cast<>s, because even QPC only has a ¼μs resolution.

In our app, a dynamic_cast<> costs about 1 microsecond, and a string comparison about 3ns/character.

Both dynamic_cast<> and stricmp() are at the top of our profiles, which means the performance cost of using them is significant. (Frankly in our line of work it's unacceptable to have those functions so high on the profile and I've had to go and rewrite a bunch of someone else's code that uses them.)

Crashworks
  • 40,496
  • 12
  • 101
  • 170
  • 2
    Whoa. `dynamic_cast` is three orders of magnitude slower than a character comparison? That’s … weird. **EDIT** Although not that weird since `dynamic_cast` may need to traverse a tree in memory (which implies random access and multiple cache misses) while a string comparison works on cached memory. – Konrad Rudolph Mar 19 '12 at 21:31
  • 1
    @KonradRudolph I could rerun the timings and post them on my blog, I suppose. The last time I ran them was a couple of years ago. Also, our class hierarchies are immense. The cost of a dynamic_cast<> increases with the number of inheritances between child and ancestor. – Crashworks Mar 19 '12 at 21:34
  • @JonasByström Thank you, but my suggestion is that you really ought to measure it yourself -- I've found that timings for dynamic_cast<> vary *hugely* depending on the size of the class tree, whether you use MSVC or GCC, and so on. The situation might be different for your app, and it should only take half an hour to set up and run a simple timing test. – Crashworks Mar 19 '12 at 22:38
  • @Crashworks Probably would take me longer, since I'm porting to four platforms - so thanks but no thanks. Even if my dynamic_cast's are 50x faster than yours (which I find unlikely), it's still slower than str==. I think it's a pretty natural conclusion that C++ builtins hardly are 200x faster or more on any one platform, let alone on all four platforms. – Jonas Byström Mar 20 '12 at 06:53
  • @JonasByström The differences can be startlingly big. The 1us/3ns ratio was for MSVC on one of the PowerPC platforms I suspect you're looking at. GCC on the other PPC platform was closer to 500ns/3ns. On x86 MSVC, dynamic_cast<> was at parity with four strcmps for small class hierarchies and frequent hits (but worse for misses on deep hierarchies). On GCC for another x86 plat, strcmp() fared worse than dynamic_cast because GCC's implementation of string compare was so poor. This particular thing is exponentially sensitive to in-order/out-of-order hardware differences. – Crashworks Mar 20 '12 at 07:01
  • @Crashworks: I understand. The "exponentially sensitive" problem would never arise on a `strcmp`, so avoiding that is another plus. I'm amazed that everybody wants me to do my own measurements when you've seen two orders of magnitude cost delta. In order to be equally bad the other way around, `dynamic_cast` would have to be four orders of magnitude faster. Good luck with that! :) – Jonas Byström Jun 29 '12 at 08:12
6

The best answer is to measure, my guess would be that dynamic_cast is faster than comparing any but the shortest strings (or perhaps even than short strings).

That being said, trying to determine the type of an object is usually a sign of bad design, according to Liskov's substitution principle you should just treat the object the same and have the virtual functions behave the correct way without examining the type from the outside.


Edit: After re-reading your question I'll stick to There is no sub-class to the one I'll be looking for. In that case you can use typeid directly, I believe it should be faster than either of your options (although looking for a specific type is still a code smell in my opinion)

#include <iostream>
#include <typeinfo>

struct top {
    virtual ~top() {} 
};

struct left : top { };
struct right : top { };

int main()
{
    left lft;
    top &tp = lft;   
    std::cout << std::boolalpha << (typeid(lft) == typeid(left)) << std::endl; 
    std::cout << std::boolalpha << (typeid(tp) == typeid(left)) << std::endl; 
    std::cout << std::boolalpha << (typeid(tp) == typeid(right)) << std::endl; 
}

Output:

true
true
false

Motti
  • 110,860
  • 49
  • 189
  • 262
  • I asked to not have to measure, the code is portable and I also don't need accuracy. I'm guessing @Crashworks measurements are approximately generic. Your second paragraph does not add any value to this question. – Jonas Byström Mar 19 '12 at 22:11
  • 1
    Did you *read* Crashwork's answer and follow-on comments? He said "I've found that timings for dynamic_cast<> vary hugely depending on the size of the class tree, whether you use MSVC or GCC, and so on." In other words, anything but generic. – David Hammen Mar 19 '12 at 22:54
  • 1
    @JonasByström I've added another solution which may be faster than both your options. – Motti Mar 20 '12 at 07:09