【问题标题】:Good way to handle a whole hierarchy of exceptions on several places在多个地方处理整个异常层次结构的好方法
【发布时间】:2012-07-02 10:13:29
【问题描述】:

我很确定这里有类似的问题,但我找不到。

假设我有几个函数,它们可能会引发整个异常层次结构 - 比如说 N 种异常类。

现在,有没有一种很好的方法来处理所有这些异常,而不是用 N catch-blocks 编写多次相同的代码?

我实现这一点的(非常丑陋的)方法是使用宏。其他想法?

所有函数都有不同的输入/输出参数和返回类型


编辑

是的,所有异常都有相同的基类——它是一个层次结构。但是不同的类有不同的附加信息。

例子:

try
{
    object->execute( ... );
}
catch( type1& ex )
{
    // ...
}
//...
catch( typeN& ex )
{
    // ...
}

// some other code
// and again:

try
{
    object->do_something_else( ... );
}
catch( type1& ex )
{
    // ...
}
//...
catch( typeN& ex )
{
    // ...
}

// and so on

【问题讨论】:

  • 如果您的异常具有相同的基类,您可以只编写一个处理程序。不清楚你想在哪里处理来自不同功能的异常。
  • @KirillKobelev - 它们具有相同的基类,是的,它是一个层次结构。但是不同的类有不同的附加信息。我将编辑我的问题以获取更多详细信息。

标签: c++ exception-handling coding-style


【解决方案1】:

创建一个名为handleExceptions(Exception&) 的函数,它引用异常的基类。

在那个函数中,你可以做任何你想做的事情,除了例外,例如调用一些特定于Exception 子类的虚拟方法。您还可以使用dynamic_cast 等定义实际的异常。

【讨论】:

    【解决方案2】:

    已经提到了通过基类捕获并将异常提供给 handleException 方法,然后该方法会打开实际的底层类型。这是另一种方法,相反:

    您可以编写一个函数exception_check,它接受一个函子并在适当的try..catch 中执行它:

    template<typename Func>
    Func exception_check(Func fun)
    {
        try
        {
            func();
        }
        catch( type1& ex )
        {...}
        //...
        catch( typeN& ex )
        {...}
        return func; //in case the functor stores a result. 
    }
    

    当然,要在不使生成的代码看起来丑陋的情况下完成这项工作,您可能需要 C++11 及其 lambda 函数,否则您会将代码分散在许多仿函数上。使用 lambda 函数,它可以简单地称为

    exception_check([&](){ object->execute(...); }); 
    exception_check([&](){ object->do_something_else(...); }); 
    

    我个人觉得这更好读然后在每个函数调用周围进行一次尝试/捕获。

    当然,在 c++11 中,对仿函数使用完美转发而不是复制它可能是个好主意。

    【讨论】:

    • 我不能使用 C++11,因为它是一个大型项目,总是为旧的特定平台(RHEL4 及其原始 gcc)编译,但这听起来不错。我还不熟悉 C++11,所以有一个问题——有没有办法为这种情况传递不同的参数?因为我想过这样的事情,但是我怎样才能传递不同的论点(如问题中所述)?
    • @KirilKirov:定义为 [&amp;](...){...} 的 lambda 将通过引用捕获 lambda 内使用的所有变量。因此[&amp;](){ object-&gt;execute(...); } 创建的仿函数存储了对其主体中提到的每个变量的引用。这意味着您只需为每个不同的调用使用不同的 lambda(毕竟它不会添加那么多输入)。如果没有 C++11,这会变得更加丑陋,因为您没有内联函子并且捕获变量是一个皮塔饼。使用 boost.Lambda 可能仍然可以使某些内容具有可读性(如果它甚至适用于您的平台),但没有那么好。
    • 这真的很棒。 +1(接受另一个答案,因为这不适用于 C++03 :( )
    • @KirilKirov:澄清一下:它可以很容易地应用于 C++03。问题在于缺少 lambda 函数可能会使代码变得更丑陋,尽管对于示例中的简单情况,例如 boost::bindstd::tr1::bind 可能工作得很好
    • 不错!我不是时候让自己熟悉 boost,尤其是像 boost::bind 这样的一些“异国情调”的东西。感谢您的信息。
    【解决方案3】:

    traget 函数的每个调用都应该有自己的 try 块,除非您可以将这些调用组合成一个内部带有 switch 的函数。

    您可以捕获基类并调用一个通用函数,该函数将使用typeid 操作或任何其他方式来区分内部可能的异常类型。由于异常应该很少发生,因此使用 RTTI 的开销可能是可以接受的。

    【讨论】:

    • 嗯,我喜欢 RTTI 的想法。我会考虑的。
    • 只要确保通过引用捕获,以避免切片。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-30
    • 1970-01-01
    • 1970-01-01
    • 2021-07-26
    相关资源
    最近更新 更多