Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ dynamic_cast error handling

Tags:

Is there any good practice related to dynamic_cast error handling (except not using it when you don't have to)? I'm wondering how should I go about NULL and bad_cast it can throw. Should I check for both? And if I catch bad_cast or detect NULL I probably can't recover anyway... For now, I'm using assert to check if dynamic_cast returned not NULL value. Would you accept this solution on a code review?

like image 542
Nazgob Avatar asked Oct 29 '08 10:10

Nazgob


People also ask

What happens when dynamic_cast fails?

If a dynamic_cast fails, the result of the conversion will be a null pointer. Because we haven't checked for a null pointer result, we access d->getName(), which will try to dereference a null pointer, leading to undefined behavior (probably a crash).

Can dynamic_cast throw exception?

dynamic_cast will no longer throw an exception when type-id is an interior pointer to a value type, with the cast failing at runtime. The cast will now return the 0 pointer value instead of throwing.

Is dynamic_cast a code smell?

Yes, dynamic_cast is a code smell, but so is adding functions that try to make it look like you have a good polymorphic interface but are actually equal to a dynamic_cast i.e. stuff like can_put_on_board .

Is Static_cast faster than dynamic_cast?

While typeid + static_cast is faster than dynamic_cast , not having to switch on the runtime type of the object is faster than any of them.


2 Answers

If the dynamic_cast should succeed, it would be good practice to use boost::polymorphic_downcast instead, which goes a little something like this:

assert(dynamic_cast<T*>(o) == static_cast<T*>(o)); return static_cast<T*>(o); 

This way, you will detect errors in the debug build while at the same time avoiding the runtime overhead in a release build.

If you suspect the cast might fail and you want to detect it, use dynamic_cast and cast to a reference type. This cast will throw bad_cast in case of error, and will take down your program. (This is good if, as you say, you are not going to recover anyway)

T& t = dynamic_cast<T&>(o); t.func(); //< Use t here, no extra check required 

Use dynamic_cast to a pointer type only if the 0-pointer makes sense in the context. You might want to use it in an if like this:

if (T* t = dynamic_cast<T*>(o)) {     t->func(); //< Use t here, it is valid } // consider having an else-clause 

With this last option you need to make sure that the execution path makes sense if the dynamic_cast returns 0.

To answer your question directly: I would prefer one of the two first alternatives I have given to having an explicit assert in the code :)

like image 82
Magnus Hoff Avatar answered Oct 11 '22 10:10

Magnus Hoff


bad_cast is only thrown when casting references

dynamic_cast< Derived & >(baseclass) 

NULL is returned when casting pointers

dynamic_cast< Derived * >(&baseclass) 

So there's never a need to check both.

Assert can be acceptable, but that greatly depends on the context, then again, that's true for pretty much every assert...

like image 43
Pieter Avatar answered Oct 11 '22 11:10

Pieter