代码之家  ›  专栏  ›  技术社区  ›  Laserallan

异常处理中的代码重用

  •  15
  • Laserallan  · 技术社区  · 15 年前

    我开发了一个C++ API,用于编写C++中的一些功能,我希望确保没有任何异常从任何导出的C函数中传播出来。

    try {
       // Do the actual code
    } catch (...) {
       return ERROR_UNHANDLED_EXCEPTION;
    }
    

    假设我知道C++代码中经常会漏掉的一个异常是STD::BADYOLL,我想特别对待它,我会写这样的东西来代替:

    try {
       // Run the actual code
    } catch (std::bad_alloc& e) {
       return ERROR_BAD_ALLOC;
    } catch (...) {
       return ERROR_UNHANDLED_EXCEPTION;
    }
    

    是否有可能以某种巧妙的方式对此进行分解,这样我就可以在全局范围内以不同的方式处理某些错误,而无需在每个导出函数周围为异常处理程序添加新的catch语句?

    6 回复  |  直到 15 年前
        1
  •  28
  •   Jem    15 年前

    对于所有可能的异常,您只能使用一个处理程序函数,并从每个或您的API实现函数调用它,如下所示:

    int HandleException()
    {
        try 
        {
            throw;
        }
    
        // TODO: add more types of exceptions
    
        catch( std::bad_alloc & ) 
        {
           return ERROR_BAD_ALLOC;
        }
        catch( ... )
        {
            return ERROR_UNHANDLED_EXCEPTION;
        }
    }
    

    try
    {
        ...
    }
    catch( ... )
    {
        return HandleException();
    }
    
        2
  •  5
  •   Abhay    6 年前

    已经有了一个很好的答案。但仅供参考,它被称为“异常调度器”的习惯用法,参见 C++ FAQ .

        3
  •  1
  •   James Hopkin    15 年前

    那么:

    try{
        //Your code here
    } catch(std::exception e)
    {
       return translateExceptionToErrorCode(e);
    } catch(...)
    {
       return UNKNOWN_EXCEPTION_THROWN;
    }
    
        4
  •  1
  •   Community Mike Causer    7 年前

    Jem

    template <class T, void (T::*FUNC)()>
    class CatchWrapper
    {
    public:
    
        static void WrapCall(T* instance)
        {
            try
            {
                (instance->*FUNC)();
            }
            catch (std::bad_alloc&)
            {
                // Do Something 1
            }
            catch (std::exception& e)
            {
                // Do Something 2
            }
            catch (...)
            {
                // Do Something 3
            }
        }
    };
    
    
    class Foo
    {
    public:
        void SomeCall()
        {
            std::cout << "Do Something" << std::endl;
        }
    };
    
    
    int main(int argc, char* argv[])
    {
        Foo i;
        CatchWrapper<Foo, &Foo::SomeCall>::WrapCall(&i);
        return 0;
    }
    
        5
  •  0
  •   1800 INFORMATION    15 年前

    永远不要使用 catch(...) ,除非你计划马上重新投掷。您肯定会丢失任何可能帮助您找出错误原因的错误信息。

        6
  •  0
  •   Carl Seleborg    15 年前

    在语言边界上丢失错误信息将是一种耻辱。您确实应该尝试将所有异常转换为可从C使用的错误代码。

    如何实现这一点实际上取决于异常类的外观。如果控制异常类层次结构,则可以确保每个类使用虚拟方法提供转换。如果没有,您可能仍然会发现使用translator函数并测试它接收到的“std::exception”派生异常的类型以将其转换为错误代码是可行的,就像Jem建议的那样(记住:抛出的异常无论如何都会影响性能,所以不要担心转换速度太慢)。