我对异常处理的理解非常有限。虽然我发现抛出异常很容易(或者我可以使用 expected<T>
打包它供以后使用),但我对如何处理异常知之甚少。
目前我的知识仅限于
清理我自己的资源并在适当的位置重新抛出要处理的异常。例如
ptr p = alloc.allocate(n); try { uninitialized_copy(first,last,p);//atomic granularity, all or none } catch(...) { alloc.deallocate(p,n); throw; }
但我想,这可以等效地转换为 RAII
模式为
alloc_guard<ptr> p{alloc.allocate(n)};
uninitialized_copy(first,last,p.get());
p.commit();
在顶层捕获异常,撰写并打印一条好消息并退出。例如
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; } }
所以,我所做的只是在顶层函数中,例如 main
捕获异常并打印适当的消息并关闭。
在使用各种外部库作为实现后端来实现具有一组不错的 API 的库时,我意识到第三方库异常是我的 API 规范的一部分,因为它们跨越了我的库边界并进入了用户代码!
因此,我的库 API 将我正在使用的外部库(每个库都有自己的异常层次结构)的所有异常泄露给了用户代码。
这引出了我的问题,当我捕获到任何异常时可以做什么?
更具体地说,
- 我能否将捕获的异常从外部库转换为我自己的异常并以通用方式抛出它(比如第三方库异常层次结构和我的异常 API 之间的映射作为
mpl::map
提供)? - 我可以做一些比打印消息/调用堆栈更有用的事情吗,比如在抛出站点使用不同的输入参数恢复函数(比如当我得到
file_not_found
或disk_error
时,重新运行函数不同的文件)? - 还有其他值得了解的模式吗?
谢谢
最佳答案
除了 nogard 所说的之外,我还想添加以下内容:
- 异常(exception)应该用于特殊的事情。不应该发生的事情。
- 如果遇到异常,至少在某处记录下来。这可能会帮助您找到错误。
- 尝试在捕获到异常时解决错误。
- 如果这不可能,请尝试保持应用程序可以继续运行的一致状态。
- 如果这不可能 - 考虑优雅地终止。
- 通知用户发生了异常情况。
最后的建议 - 保持错误处理的一致性。这包括将第三方库中的异常转换为您的异常层次结构。
回复评论:
2) 异常应该包含出错的信息。这可能只是类型或一些附加信息。在客户处记录这些信息可以让您获得更多关于实际出了什么问题的信息,而不仅仅是客户告诉您的内容。也许他滥用了您的应用程序,发现了另一个用例,或者您只是有一个错误(例如,一个未初始化的变量)。但是有了这些额外的信息,您就可以找到出错的位置以及有关出错原因的一些信息。这有助于您推断错误的来源,从而找到错误。
3) 这实际上取决于发生的错误。例如。您尝试访问一个不存在的配置文件 --> 您创建一个具有默认值的新配置文件。客户端尝试打开数据库进行写访问,但它是写保护的。您拒绝打开,返回有效状态并告诉客户端数据库已写保护。内存不足无法继续?记录这个(注意 - 你没有备用内存,所以你的日志记录应该已经为这个用例预留了一些内存)并优雅地关闭应用程序。也许,如果可能的话,通知客户。
关于来自其他库的代码:没有其他方法可以检查对另一个库的每个函数调用是否有可能返回的异常并捕获它们。一旦被捕获,您可以将信息从该异常转移到您的异常中并抛出该异常(或以其他方式解决它)
关于c++ - catch 站点异常的常见用法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18200900/