catch站点的异常常见用法是什么?

abi*_*bir 7 c++ exception-handling exception try-catch c++11

我对异常处理的理解非常有限.虽然我发现很容易抛出异常(或者我可以将它打包expected<T>用于以后的消费),但我对如何处理异常几乎一无所知.

目前我的知识仅限于

  • 清理我自己的资源并重新抛出要在适当位置处理的异常.例如

    ptr p = alloc.allocate(n);
    try
    {
       uninitialized_copy(first,last,p);//atomic granularity, all or none
    }
    catch(...)
    {
        alloc.deallocate(p,n);
        throw;
    }
    
    Run Code Online (Sandbox Code Playgroud)

但我想,这可以在一个RAII模式中等效地转换为

alloc_guard<ptr> p{alloc.allocate(n)};
uninitialized_copy(first,last,p.get());
p.commit();
Run Code Online (Sandbox Code Playgroud)
  • 在顶层捕获异常,撰写并打印一条好消息并退出.eg

    int main(int argc,char** argv)
    {
       try
       {
           app_t the_app(argc,argv);
           the_app.run();
       }
       catch(std::runtime_error& e)
       {
          //instead of what, I can also compose the mesage here based on locale.
          std::cout<<e.what()<<std::endl;
       }
    }
    
    Run Code Online (Sandbox Code Playgroud)

所以,我所做的就是处于顶级功能,例如main捕获异常并打印相应的消息并关闭.

在使用各种外部库作为实现的后端实现具有一组良好API的库时,我意识到第三方库异常是我的API规范的一部分,因为它们跨越我的库边界并落在用户代码中!

因此,我的库API泄露了我用于用户代码的外部库(并且每个库都有自己的异常层次结构)的所有异常.

这导致了我的问题,当我发现任何异常时可以做些什么?

进一步来说,

  • 我可以将捕获的异常从外部库转换为我自己的异常并以通用方式抛出(比如第三方库异常层次结构和我的异常API之间的映射是作为a提供的mpl::map)吗?
  • 我可以做一些比打印消息/调用堆栈更有用的东西,比如使用不同的输入参数恢复抛出站点的功能(比如当我得到那个file_not_found或者disk_error,用另一个文件重新运行该函数)?
  • 还有其他有价值的模式吗?

谢谢

nog*_*ard 2

这是一个非常大的话题。

  1. 我怀疑您是否可以轻松地将第三方异常转换为您自己的异常,而且我个人认为没有必要实现这种行为。由于第 3 方库是您的实现的一部分,它没有公开给公共 API,为什么您要公开它的所有异常(即使通过一些映射)?如果有一天您坚持使用另一个实现相同内容的第三方库 - 您愿意重新设计整个异常层次结构吗?我想不是。你的库的 API 一定不能脆弱,所以我建议不要将外部异常映射到你自己的异常。

  2. 您可以通过以下方式将第 3 方例外映射到您的层次结构:

    • 根本不要包裹任何东西。我的意思是你不必仅仅因为第三个图书馆这样做就扔掉任何东西。您可以捕获该异常并处理它,或者返回错误代码,或者适当地更改状态。除了总是重新抛出之外,还有许多其他可能性。

    • 您不必对所有第 3 方例外情况进行一对一翻译。如果您在内部使用库 AAA,那么您可以使用单个 AAAException 来表示来自该库的许多异常。

  3. 值得了解的是:始终通过 const 引用捕获异常:

    catch (const exception & ex)

这个话题很大,希望我的回答有助于理解。

对评论的答复:

  1. 如果我不将第三方异常映射到我自己的 API(不需要一对一),它们就会泄漏到客户端代码- 不,他们不会,这就是重点!您必须在库中捕获它们,然后决定如何处理捕获的异常:抛出您自己的异常、返回错误代码、通知客户端侦听器、记录错误等...

    try {
        3rdpatry.call();
    } catch (const 3rdpartyException & ex) {
        // throw YourException(ex.what());
        // listener.notify(some_error)
        // return some_code
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 通过 const 引用捕获根本不是为了防止切片。这里有一个很好的讨论解释了这一点。