如何抛出,试试{} catch {}应该在现实世界中使用?

Joh*_*ang 6 c++ exception try-catch throw

我的意思是,我知道关于throw的所有语言规则,尝试{} catch {},但我不确定我是否在现实世界中正确使用它们.请参阅以下示例:

我们有大量的科学代码可以完成各种图像处理工作,最近我们决定对其进行修改,使其更加强大.经常使用的一个例程是void rotate_in_place(float*image,image_size sz) ;

为了使其更加健壮,我们在代码的开头添加了一些健全性检查:

void rotate_in_place(float* image, image_size sz) {
    // rotate_in_place does not support non-square image;
    if (sz.nx != sz.ny)  throw NonSquareImageError;
    // rotate_in_place does not support image too small or too large
    if (sz.nx <= 2 || sz.nx > 1024)  throw WrongImageSizeError;
    // Real rode here
    .....
}
Run Code Online (Sandbox Code Playgroud)

现在的问题是rotate_in_place()在1000多个地方使用,我应该用try {} catch {}包装每次调用rotate_in_place(),这对我来说会让代码难以置信地膨胀.另一种可能性是不包装任何try {} catch {}并让程序退出,但这与仅使用有什么不同

if (sz.nx != sz.ny) {
    cerr << "Error: non-squared image error!\n";
    exit(0);
}
Run Code Online (Sandbox Code Playgroud)

简而言之,我不太确定使用throw,try,catch,任何好建议的真正好处?

Cat*_*lus 6

处理错误的每个站点都需要try- catch阻止.这一切都取决于你的设计,但我怀疑你需要在每个rotate_in_place呼叫站点处理错误,你可能在大多数时间都不会向上传播.

打印错误和使用exit是不好的有三个原因:

  1. 你无法处理错误.exit没有处理(除非在错误绝对严重时完成,但你的功能无法知道 - 调用者可能有办法恢复).
  2. 您正在通过写入硬编码流来扩展函数的职责,这可能甚至不可用(这rotate_in_place不是rotate_in_place_and_print_errors_and_kill_the_program_if_something_is_wrong) - 这会损害可重用性.
  3. 使用这种方法会丢失所有调试信息(您可以从未处理的异常中生成堆栈跟踪,您不能对每次执行的函数执行任何操作 - 未处理的异常是一个错误,但这是您可以遵循的错误) .


Bil*_*eal 5

例外的一般规则是,"即时呼叫站点是否关心这里发生了什么?" 如果呼叫站点确实关心,那么返回状态代码可能是有意义的.否则,投掷更有意义.

以这种方式考虑 - 当然,你的rotate in place方法有几个无效的参数类型,在这种情况下你应该抛出std::invalid_argument.例如,rotate_in_place想要处理或知道如何处理图像不是正方形的情况的调用者不太可能,因此可能更好地表示为异常.

另一种可能性是不包装任何try {} catch {}并让程序退出,但这与仅使用有什么不同

if (sz.nx != sz.ny) {
    cerr << "Error: non-squared image error!\n";
    exit(0);
}
Run Code Online (Sandbox Code Playgroud)

这是不同的,因为如果有人后来想要将您的功能放入GUI应用程序中,则他们不必根据错误终止程序.他们可以将该异常转化为适合用户或类似的东西.

它现在对你也有好处 - 也就是你不必<iostream>简单地写入错误写入翻译单元.

我通常使用这样的模式:

int realEntryPoint()
{
    //Program goes here
}

int main()
{
    //Allow the debugger to get the exception if this is a debug binary
    #ifdef NDEBUG
    try
    #endif
    {
      return realEntryPoint();
    }
    #ifdef NDEBUG
    catch (std::exception& ex)
    {
      std::cerr << "An exception was thrown: " << ex.what() << std::endl;
    }
    #endif
}
Run Code Online (Sandbox Code Playgroud)