Archived

This topic is now archived and is closed to further replies.

Zoomby

dynamic_cast or ordinary cast?

Recommended Posts

hi, What is the difference between the two casts below? The only thing I know is, that dynamic_cast can return NULL. But how expensive is it to use dynamic_cast and the other cast operators? Mammal* m=new Cat(); Cat* cat=(Cat*)m; Cat* cat=dynamic_cast(m); bye chris

Share this post


Link to post
Share on other sites
I know a normal cast is free... I'm not to sure about a dynamic_cast.

In binary... all pointers have no type, they are simply memory locations. Doing a normal cast just tells the compiler that you know you are going from one type to another (type checking). It doesn't actually change anything, and still simply sets the pointer cat to the address stored in m. There is nothing else going on behind the scenes.


--- Edit ---
Made a simple typing correction.

[edited by - Ready4Dis on May 6, 2003 10:02:01 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Ready4Dis
I know a normal cast is free...

No it is not! A so-called `normal'' cast, by which I assume you mean a C-style cast can mean one of several things. C++ breaks the different forms of cast down into explicit constructs for static_cast, dynamic_cast, const_cast and reinterpret_cast. None of the casts are free by any decent definition of the word. There is always some associated cost, whether it be at compile-time or run-time, or in terms of const-correctness or platform neutrality. There is always a price to pay.
quote:

I''m not to sure about a dynamic_cast.

A dynamic_cast is sometimes a symptom of a poor design. If that is the case, then the cost of dynamic_cast should be the least of your worries. If you genuinely need one, then you pay the price for a quick RTTI check. But then, if you genuinely need one, then there''s no escaping the cost. It''s only unnecessary overhead if you don''t actually need it.

Share this post


Link to post
Share on other sites
He was asking how expensive the casts were, not how long they take to compile. So my statement about it being "free" still stands true. You HAVE to use a cast, so arguing that it takes time to compile is a mute point, because any cast will have to be processed at compile time. He was asking which was more expensive (aka, which takes more clock cycles), and a "normal" cast takes none.

Share this post


Link to post
Share on other sites
I just checked the disassembly of both casts. The "C-Sytle" cast is just copying the adresse, while the dynamic_cast is calling a function which is very large (in assembler).
Now what is this function doing and how fast is it? If there is such a overhead, does anyone use dynamic_cast in time-critical software like games?

Share this post


Link to post
Share on other sites
quote:
Original post by Ready4Dis
He was asking how expensive the casts were, not how long they take to compile.

He didn''t say in which sense he meant it. It is perfectly valid for `expensive'' to mean `it makes my program harder to understand'' or `it makes my program take longer to compile'' or even `it costs more money to write''. Some people will happily pay for a miniscule amount of CPU if it helps provide assurances about application stability.
quote:

You HAVE to use a cast, so arguing that it takes time to compile is a mute point, because any cast will have to be processed at compile time.

Nonsense. Some casts can only take place at run-time. In the OP''s case, it''s not exactly clear what sort of cast he wants as he hasn''t provided enough information. It is a downcast, but I don''t know if it will have to be a static or dynamic downcast. If it has to be a dynamic_cast, then the associated cost cannot be escaped.

Share this post


Link to post
Share on other sites
quote:
Original post by Zoomby
If there is such a overhead, does anyone use dynamic_cast in time-critical software like games?
No. In time critical software they don't even call a single function because the overhead is so big. They inline everything by hand just to make sure it gets inlined. And then they code most of the GUI in ASM.



[edited by - civguy on May 6, 2003 10:37:04 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Zoomby
Now what is this function doing

It is checking that the dynamic type of the pointer is either of the type specified in the cast, or an accessible base of the type specified. If it is one of those, then it is yielding a converted pointer, if not it will yield NULL.
quote:

If there is such a overhead, does anyone use dynamic_cast in time-critical software like games?

People tend to try and avoid dynamic_cast in general, if it can be helped. Counter-examples include things like the Visitor idiom, which is an approximation of dual dynamic despatch.

Share this post


Link to post
Share on other sites
Zoomby: What do you use as your main c++ reference? If you''re using microsoft it comes with plenty of material. I''d recommend getting a good book as well though.

Do you know what dynamic_cast does?

It will work out at runtime whether the pointed to object is related to the type you''re trying to cast it to i.e. if it is derived from the type you are casting it to.

If it isn''t it will return 0.
If it is it will return a pointer to the correct type.

Your program must then decide what to do. You can''t use the zero pointer or your program will exhibit undefined behaviour.

If your program requires it there is quite likely something wrong with your design. There are cases where it is arguably the best soultion to a problem but it is unlikely that you are in that territory.

Share this post


Link to post
Share on other sites
quote:
Original post by SabreMan
He didn''t say in which sense he meant it. It is perfectly valid for `expensive'' to mean `it makes my program harder to understand'' or `it makes my program take longer to compile'' or even `it costs more money to write''. Some people will happily pay for a miniscule amount of CPU if it helps provide assurances about application stability.



If he''s asking how expensive 2 operations are, especially casts, you can pretty much assume he means compiled. This is further follewed by his statements about comparing the assembly output, in which case we can see, my assumptions were correct. By using syntactical clues as well as the level of programmer he appears to be on, you can normally figure out what they are trying to say, even if they don''t blatantly say so.


quote:
Original post by SabreMan
Nonsense. Some casts can only take place at run-time. In the OP''s case, it''s not exactly clear what sort of cast he wants as he hasn''t provided enough information. It is a downcast, but I don''t know if it will have to be a static or dynamic downcast. If it has to be a dynamic_cast, then the associated cost cannot be escaped.


Yes.. SOME, but in this case, you have to use a cast, that''s just the way it is. Sure if he was using a void *ptr, it would have an automatic cast conversion, or you could over-load a cast to that type, but that''s still using a cast. Arguing differing cases doesn''t help prove anything. The point remains that in THIS case, he needs to use some cast, he is worried about which cast will cost him the most time/cycles. So, like I said... the "normal" cast is free. It takes the least time to compile and once compiled is completely gone. I have never used a dynamic_cast, so I didn''t/can''t comment on it, other than that he looked at the assembly output and it calls another function, so it will ALWAYS be slower, but if it''s not in a time critical section, won''t matter.

Share this post


Link to post
Share on other sites
quote:
Original post by Ready4Dis
If he''s asking how expensive 2 operations are, especially casts, you can pretty much assume he means compiled.

Good programmers prefer to keep away from unwarranted assumptions.
quote:

By using syntactical clues as well as the level of programmer he appears to be on, you can normally figure out what they are trying to say, even if they don''t blatantly say so.

You do realise that you still can''t answer the OP''s question with certainty? There is no way of telling what sort of cast he needs. Unless you''ve also assumed things about his program that are not apparent from the toy example he posted, that is.
quote:
Original post by SabreMan
Yes.. SOME, but in this case, you have to use a cast, that''s just the way it is.

I''m not sure why you think I''ve argued against that point.
quote:

So, like I said... the "normal" cast is free.

A reinterpret_cast is not equivalent to a dynamic_cast, so you should not conclude that the reinterpet_cast is `free''.

Share this post


Link to post
Share on other sites
This is all from memory and is untested.

Taking your example:

Cat* cat=(Cat*)m;
Cat* cat=dynamic_cast(m);

A C style cast turns whatever is in the address m into a cat. If m isn''t a class in m''s hierarchy, then you just created a bad pointer (ie you have a cat pointer to something that isn''t a cat). For instance, with C style casts, this would be legal:

int i;
Cat* cat=(Cat*)&i;

If you try to use the cat pointer, you are in trouble.

A dymanic_cast walks through the inheritance path, preventing the case above (in fact, I don''t believe this would work because int doesn''t have a virtual destructor, so there isn''t any information for dynamic_cast to use -- probably a compile time failure, with it suggesting another cast type.

Now, walking the inheritance path can be expensive. The time required is compiler and hierarchy shape dependant. This definitely isn''t something you would want to do in an inner loop, but that doesn''t mean that it doesn''t have have a place in a game (performance-wise -- Sabre already hit the design issues well).

Another alternative would be to have a macro-cast which, in debug, did a dynamic_cast and asserted if it failed, and in release did a Cstyle cast.

This can be particularly useful if you inherited someone elses code and suspect that they may have been a bit too loose with their unsafe (cstyle/reinterpret) casts.

Share this post


Link to post
Share on other sites
quote:
Original post by Ready4Dis
the "normal" cast is free. It takes the least time to compile and once compiled is completely gone.


No. Even static_cast and "C-style" casts have run-time costs for many cases because the new pointer value needs to be calculated. The cost may be negligible but the operation is by no means guaranteed to be "free".

[edited by - spock on May 6, 2003 11:41:23 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by spock
[quote]Original post by Ready4Dis
the "normal" cast is free. It takes the least time to compile and once compiled is completely gone.


No. Even static_cast and "C-style" casts have run-time costs for many cases because the new pointer value needs to be calculated. The cost may be negligible but the operation is by no means guaranteed to be "free".

[edited by - spock on May 6, 2003 11:41:23 AM]

Ummm... if you''re casting from one pointer type to another, there is actually NO cost with a C-style cast at runtime. Period. The memory address remains unchanged. Casts are for the benefit of the compiler (except for dynamic_cast, which uses RTTI).

Share this post


Link to post
Share on other sites
quote:
Original post by daerid
The memory address remains unchanged. Casts are for the benefit of the compiler (except for dynamic_cast, which uses RTTI).


The memory address does not necessarily remain unchanged when you are casting between pointer types in an inheritance hierarchy, which is a common case. If the pointer value does not need to be changed there will be no runtime cost, of course.

Share this post


Link to post
Share on other sites
quote:
Original post by spock
The memory address does not necessarily remain unchanged when you are casting between pointer types in an inheritance hierarchy, which is a common case. If the pointer value does not need to be changed there will be no runtime cost, of course.


Please read my entire post. I qualified that statement with the use of a C-style cast.

If you use a C-style cast, you will not change the address that that pointer points to. Period. Unless you do pointer arithmetic, it won''t change.

Share this post


Link to post
Share on other sites
Well, I may have misunderstood what you said. Here''s an example intended to illustrate what I''m talking about:


struct A { int a; };
struct B { int b; };
struct C : public A, public B { int c; };
int main()
{
C* c = new C;
printf("%p %p\n",(A*)c,(B*)c);
}


Those are C-style casts, right? Surely this must result in two distinct pointer values being printed by the printf call, with an associated calculation being done at runtime?

Share this post


Link to post
Share on other sites
quote:
Original post by spock
Well, I may have misunderstood what you said. Here's an example intended to illustrate what I'm talking about:


struct A { int a; };
struct B { int b; };
struct C : public A, public B { int c; };
int main()
{
C* c = new C;
printf("%p %p\n",(A*)c,(B*)c);
}


Those are C-style casts, right? Surely this must result in two distinct pointer values being printed by the printf call, with an associated calculation being done at runtime?


Hmm... yes, I'll have to rescind my previous statement. But at the absolute most, all you'll get is a single pointer addition at runtime. And only when dealing with inheritance in C++.

[edited by - daerid on May 6, 2003 9:02:25 PM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
quote:
Surely this must result in two distinct pointer values being printed by the printf call


nope

Share this post


Link to post
Share on other sites
AP, did you actually try it? How do you think the base classes can both be stored at the same base address? Why am I wasting my time replying to you? These questions, and many more, after these messages!


How appropriate. You fight like a cow.

Share this post


Link to post
Share on other sites
quote:
Surely this must result in two distinct pointer values being printed by the printf call, with an associated calculation being done at runtime


The offset can be calculated at compile time.

Share this post


Link to post
Share on other sites
quote:
Original post by daerid
Hmm... yes, I''ll have to rescind my previous statement. But at the absolute most, all you''ll get is a single pointer addition at runtime. And only when dealing with inheritance in C++.



Inheritance is the only portable example I can come up with, but it''s not safe to assume that pointer adjustment will never be needed in other cases. I would say it''s safe to assume there''s no significant cost involved, although this isn''t guaranteed by the language.

quote:
Original post by petewood
The offset can be calculated at compile time.


Yes, but the new pointer value needs to be determined at runtime and so a calculation is required. The cast becomes a lea instruction on my x86 compiler, for example.

Share this post


Link to post
Share on other sites