在C ++中重用异常处理代码

时间:2017-12-30 17:51:25

标签: c++ c++11 exception-handling

我有这两个函数,带有重复的异常处理,其唯一目的是显示错误消息:

void func1() noexcept {
  try {
    do_task();
    do_another_task();
  } catch (const std::out_of_range& e) {
    show_msg("Out of range error", e.what());
  } catch (const std::logic_error& e) {
    show_msg("Logic error", e.what());
  } catch (const std::system_error& e) {
    show_msg("System error", e.what());
  } catch (const std::runtime_error& e) {
    show_msg("Runtime error", e.what());
  } catch (const std::exception& e) {
    show_msg("Generic error", e.what());
  }
}

void func2() noexcept {
  try {
    do_something();
    do_something_else();
    do_even_more();
  } catch (const std::out_of_range& e) {
    show_msg("Out of range error", e.what());
  } catch (const std::logic_error& e) {
    show_msg("Logic error", e.what());
  } catch (const std::system_error& e) {
    show_msg("System error", e.what());
  } catch (const std::runtime_error& e) {
    show_msg("Runtime error", e.what());
  } catch (const std::exception& e) {
    show_msg("Generic error", e.what());
  }
}

我可以处理std::exception并显示一条通用消息,但我希望更具体,这就是我捕捉所有可能异常的原因。

我想重用这个异常处理代码。我想到了这个:

void run_treated(std::function<void()> func) noexcept {
  try {
    func();
  } catch // ... all the catches go here
}

void func1() noexcept {
  run_treated([]()->void {
    do_task();
    do_another_task();
  });
}

void func2() noexcept {
  do_something();
  do_something_else();
  do_even_more();
}
  1. 这是一个好方法吗?
  2. 如果是这样,run_treated将被称为很多。我应该关注表现吗?
  3. 还有其他方法吗?

2 个答案:

答案 0 :(得分:8)

  

这是一个好方法吗?

是。它可以防止代码重复,并允许您通过传入lambda轻松自定义行为。

  

如果是这样,run_treated将被大量调用。我应该关注表现吗?

是。 std::function 是零成本抽象。您应该使用模板参数来传递lambda而不需要类型擦除。

template <typename F>
void run_treated(F&& func) noexcept {
  try {
    std::forward<F>(func)();
  } catch // ... all the catches go here
}

我讨论并测试各种技术以将函数传递给本文中的其他函数:"passing functions to functions"

如果您不想使用模板传递func,则可以使用类似function_ref (建议用于标准化P0792的内容。这里有一个实现:function_ref.cpp

无关评论:

  • 那些无条件的noexcept说明符看起来很可疑。你能真正保证没有例外可以逃脱这些功能吗?

  • []()->void {}相当于[]{}

答案 1 :(得分:7)

可以选择使用Lippincott Function来集中异常处理逻辑。考虑一下:

Traceback (most recent call last):
 File "C:\Users\kashy\Desktop\trial1.py", line 29, in <module>
train_datagen = ImageDataGenerator(
NameError: name 'ImageDataGenerator' is not defined

它是如何工作的?当您在void Lippincott () noexcept { try { throw; } catch (const std::out_of_range& e) { show_msg("Out of range error", e.what()); } catch (const std::logic_error& e) { show_msg("Logic error", e.what()); } catch (const std::system_error& e) { show_msg("System error", e.what()); } catch (const std::runtime_error& e) { show_msg("Runtime error", e.what()); } catch (const std::exception& e) { show_msg("Generic error", e.what()); } } void func1() noexcept { try { do_task(); do_another_task(); } catch (...) { Lippincott(); } } void func2() noexcept { try { do_something(); do_something_else(); do_even_more(); } catch (...) { Lippincott(); } } func1中输入处理程序时,会处理“当前例外”。 func2的主体启动一个新的try..catch块并重新抛出它。然后它捕获适当的异常并相应地以集中方式处理它们。

您还应该注意,您的异常处理逻辑不是真的 Lippincott。理论上可能存在列表未涵盖的例外情况。在这种情况下,noexcept有多个地方可供调用,具体取决于您如何标记std::terminate