Jump to content
  • Advertisement
Sign in to follow this  
Numsgil

dynamic_cast in MSVC

This topic is 3585 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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?

Share this post


Link to post
Share on other sites
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...

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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.



Share this post


Link to post
Share on other sites
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 :)

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!