dynamic_cast in MSVC

Started by
31 comments, last by Numsgil 15 years, 7 months ago
Visual Studio (C++) apparently does a string compare when you call dynamic_cast, to handle edge cases of inheriting across assembly boundaries. This makes an operation that wasn't all that fast to begin with excruciatingly slow. Is there a way to tell the compiler not to do that? Let it assume that all libraries will either be static linked or not have classes inherit across assembly boundaries?
[size=2]Darwinbots - [size=2]Artificial life simulation
Advertisement
It should only ever need to do pointer compares, which are quite fast. Have you profiled it? Have you looked at the assembly? Unless you can measure that it's slower, then it's not really worth worrying about...
Quote:Original post by bgarney
It should only ever need to do pointer compares, which are quite fast. Have you profiled it? Have you looked at the assembly? Unless you can measure that it's slower, then it's not really worth worrying about...

No, he's right. MSVC's dynamic_cast will perform a full string comparison between class names. If you've got a deep hierarchy, it is indeed very slow. If you see strcmp bubbling to the top in the profiler, dynamic_cast is a possible suspect.

Unfortunately, I don't believe any such compiler switch exists. The best solution, if possible, would be to eliminate the need for dynamic_cast in the first place.
NextWar: The Quest for Earth available now for Windows Phone 7.
Quote:Original post by Sc4Freak
Quote:Original post by bgarney
It should only ever need to do pointer compares, which are quite fast. Have you profiled it? Have you looked at the assembly? Unless you can measure that it's slower, then it's not really worth worrying about...

No, he's right. MSVC's dynamic_cast will perform a full string comparison between class names. If you've got a deep hierarchy, it is indeed very slow. If you see strcmp bubbling to the top in the profiler, dynamic_cast is a possible suspect.

Unfortunately, I don't believe any such compiler switch exists. The best solution, if possible, would be to eliminate the need for dynamic_cast in the first place.


Yeah, right now it's all tucked in level initialization code, so it's not slowing the game down, but it's just a pain that it's doing that. And it limits me to only really using it during initialization. And it makes it a hard sell to other programmers who are just C casting instead. I really only use it for things like this:

class A { virtual ~A(); };class B : public A { };A *APointer = new B();...B *BPointerQuery = dynamic_cast<B *>(APointer);if(BPointerQuery)    //...


That is, I'm upcasting to a universal base class, then downcasting back to the original type. I could implement my own RTTI system, using virtual functions, but it's a pain to maintain.

Is there a way to build my own hacky version of a RTTI by somehow fiddling with the virtual table pointer? It would only need to be MSVC specific, since I think MSVC is the only one that does it like this. And it can be much stupider than the usual dynamic_cast since I'm only interested in upcasting then downcasting back to the same type. Something like this(?):

#define HACKY_POINTER_DYNAMIC_CAST(DesiredType, Pointer)     #ifdef _MSC_VER        // hacky    #else        dynamic_cast<DesiredType *>(Pointer)#endif


(I know there are some macro tricks I should use here that I'm not, but it's purely a quick and dirty example). Or maybe use templates so I can still use the label<Type *>(pointer) format.

[Edited by - Numsgil on September 19, 2008 1:38:22 PM]
[size=2]Darwinbots - [size=2]Artificial life simulation
Quote:Original post by Numsgil

Is there a way to build my own hacky version of a RTTI by somehow fiddling with the virtual table pointer?



Yes but it's VERY hacky and VERY scary. It requires using implementation details of how MSVC stores vtable pointers and using some assembly to modify portions of your code. SiCrane talks about it in detail towards the end of this thread.



Quote:Original post by MJP
Quote:Original post by Numsgil

Is there a way to build my own hacky version of a RTTI by somehow fiddling with the virtual table pointer?



Yes but it's VERY hacky and VERY scary. It requires using implementation details of how MSVC stores vtable pointers and using some assembly to modify portions of your code. SiCrane talks about it in detail towards the end of this thread.


Heh, that's a bit too hacky and scary :)
[size=2]Darwinbots - [size=2]Artificial life simulation
Quote:Original post by Numsgil
Quote:Original post by Sc4Freak
Quote:Original post by bgarney
It should only ever need to do pointer compares, which are quite fast. Have you profiled it? Have you looked at the assembly? Unless you can measure that it's slower, then it's not really worth worrying about...

No, he's right. MSVC's dynamic_cast will perform a full string comparison between class names. If you've got a deep hierarchy, it is indeed very slow. If you see strcmp bubbling to the top in the profiler, dynamic_cast is a possible suspect.

Unfortunately, I don't believe any such compiler switch exists. The best solution, if possible, would be to eliminate the need for dynamic_cast in the first place.


Yeah, right now it's all tucked in level initialization code, so it's not slowing the game down, but it's just a pain that it's doing that. And it limits me to only really using it during initialization.


Limiting the use of dynamic_cast is the way it should be, you shouldn't be seeking to change that. An abundance of dynamic_casts (or any type of cast, really) points to design problems.

Quote:I really only use it for things like this:

class A { virtual ~A(); };class B : public A { };A *APointer = new B();...B *BPointerQuery = dynamic_cast<B *>(APointer);if(BPointerQuery)    //...


That is, I'm upcasting to a universal base class, then downcasting back to the original type. I could implement my own RTTI system, using virtual functions, but it's a pain to maintain.


If you're design isn't malleable enough right now to restructure things such that dynamic_cast isn't needed, then you might consider a variant of the visitor pattern.

Or you could do something even simpler by adding a virtual function to your hierarchy that does something in B's overridden implementation, but nothing by default. It's not particularly neat, but it's no worse than your casts.

Quote:Is there a way to build my own hacky version of a RTTI by somehow fiddling with the virtual table pointer? It would only need to be MSVC specific, since I think MSVC is the only one that does it like this. And it can be much stupider than the usual dynamic_cast since I'm only interested in upcasting then downcasting back to the same type. Something like this(?):



Don't even go there :)

IMHO, it would be better to get out of this "it's ok to use dynamic_cast a lot" mindset.
Quote:Original post by the_edd
Limiting the use of dynamic_cast is the way it should be, you shouldn't be seeking to change that. An abundance of dynamic_casts (or any type of cast, really) points to design problems.


That depends. Should we avoid dynamic casts because they're slow, or because they lead to bad designs? A program in another language using dynamic typing is certainly valid if that's how the language is meant to be used. Ruby for example. I haven't done much dynamic typing myself, but I recognize lots of strengths from it.

I would say you should avoid dynamic casts because they're slow, not because there's something inherently less flexible, or more risky, about a design incorporating them. Well, that and C++ is really built to be statically typed, and you're kind of twisting it to be dynamically typed. So you might code yourself in to a dead end with language limitations. But at its core I don't think there's anything evil about dynamic casting. Or I haven't seen any evidence of it anyway.
[size=2]Darwinbots - [size=2]Artificial life simulation
Checking a type with if/else is always a bad design.
If you want to check different possibilities of types, you should perform an actual visitation, which will actually scale and won't allow you to forget cases.
Quote:Original post by loufoque
Checking a type with if/else is always a bad design.
If you want to check different possibilities of types, you should perform an actual visitation, which will actually scale and won't allow you to forget cases.


Sure if you're essentially switch casing on every possible case you're probably better off restructuring a bit. I mean more things like this:

void SerializeToNetwork(Object *Ob){    INetworkable *network = dynamic_cast<INetworkable *>(Ob);    if(network)        network->SendNetworkData();}


The idea being you don't want to pollute the def of Object with networking logic, but you want to be able to catch when an object implements the Networkable interface. There's probably other ways of doing this, but what's inherently bad about a design like this? (I don't mean this rhetorically, I'm honestly asking).

Note, this isn't actually the case I have in my code right now, this is just a hypothetical example.
[size=2]Darwinbots - [size=2]Artificial life simulation

This topic is closed to new replies.

Advertisement