c++ dynamic_cast error handling

后端 未结 5 1002
情话喂你
情话喂你 2021-02-07 01:05

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 th

相关标签:
5条回答
  • 2021-02-07 01:29

    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...

    0 讨论(0)
  • 2021-02-07 01:33

    It depends... ;-)

    If I really expected the dynamic_cast to give me something usable, for example if I and no one else added a polymorphic type to a container of pointers to a base class, then I would go with the reference cast and let the std::bad_cast kill my application - there wouldn't be much else to do, really.

    However, if I'm querying a polymorphic type for some capability exposed by an interface that it doesn't necessarily have to implement, then I'd go with the pointer cast and then a NULL wouldn't be an error (unless, of course, I expected the capability to really be there - but then I'd had gone for the reference cast in the first place...)

    0 讨论(0)
  • 2021-02-07 01:40

    Yes and no.

    boost::polymorphic_downcast<> is surely a good option to handle errors of dynamic_cast<> during the debug phase. However it's worth to mention that polymorphic_downcast<> should be used only when it's possible to predict the polymorphic type passed at compile time, otherwise the dynamic_cast<> should be used in place of it.

    However a sequence of:

    if (T1* t1 = dynamic_cast<T1*>(o)) 
    { }
    if (T2* t2 = dynamic_cast<T2*>(o)) 
    { }
    if (T3* t3 = dynamic_cast<T3*>(o)) 
    { }
    

    denotes a very bad design that should be settle by polymorphism and virtual functions.

    0 讨论(0)
  • 2021-02-07 01:43

    I'd concur with the 'it depends' answer, and also add "Graceful degradation": just because a cast fails somewhere isn't enough reason to let the application fail (and the user lose his/her work, etc.). I'd recommend a combination of asserts and defensive programming:

    ptr = dynamic_cast<MyClass>(obj);
    ASSERT(ptr);
    if(ptr)
    {
       // do stuff
    }
    
    0 讨论(0)
  • 2021-02-07 01:45

    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 :)

    0 讨论(0)
提交回复
热议问题