我对异常处理的理解非常有限。虽然我发现很容易抛出异常(或者我可以使用expected<T>
将其打包以供以后使用),但我对如何处理异常几乎一无所知。
目前我的知识仅限于
清理自己的资源并重新抛出要在适当位置处理的异常。 e.g。
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();
在顶层捕捉异常,撰写&amp;打印一条好消息然后退出.g。
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规范的一部分,因为它们跨越我的库边界并落在用户代码中! / p>
因此,我的库API泄露了我用于用户代码的外部库(并且每个都有自己的异常层次结构)的所有异常。
这导致了我的问题,当我发现任何异常时可以做些什么?
更具体地说,
mpl::map
提供的吗?)file_not_found
或disk_error
时,使用不同的文件运行该函数)?由于
答案 0 :(得分:4)
除了nogard所说的我想添加以下内容:
最终建议 - 保持错误处理的一致性。这包括将第三方库中的异常转换为异常层次结构。
评论答案:
2)例外应包含有关出错的信息。这可能只是类型或一些其他信息。通过在客户处记录这些信息,您可以获得有关客户告诉您的实际问题的更多信息。也许他误用了你的应用程序,发现了另一个用例,或者你只是有一个bug(例如一个未初始化的变量)。但是,通过这些额外的信息,您可以找到出错的位置以及出现问题的一些信息。这有助于您推断出错误的来源,从而找到错误。
3)这实际上取决于正在发生的错误。例如。您尝试访问不存在的配置文件 - &gt;您使用默认值创建一个新的。客户端尝试打开数据库以进行写访问,但它是写保护的。您拒绝打开,返回到有效状态并告诉客户端数据库是写保护的。你内存不足而无法继续?记录下来(请注意 - 您没有备用内存,因此您的日志记录应该已经为此用例预先保留了一些内存)并正常关闭应用程序。也许,如果可能的话,通知客户。
关于来自其他库的代码:除了它可能返回并捕获它们的异常之外,没有其他方法可以检查对另一个库的每个函数调用。一旦被捕获,您可以将该异常中的信息传输到您的一个中并抛出该异常(或以其他方式解决)
答案 1 :(得分:2)
这是一个非常大的主题。
我怀疑您可以轻松地将第三方异常转换为您自己的异常,而且我个人认为没有必要实现此行为。由于第三方库是您的实现的一部分,而未暴露给公共API,为什么要公开它的所有异常(甚至通过一些映射)?如果有一天你坚持使用另一个实现相同内容的第三方库 - 你想重新设计整个异常层次结构吗?我想不是。您的图书馆的API不能是脆弱的,所以我建议不要将外部例外映射到您自己的例外。
您可以按照以下方式将第三方例外映射到您的层次结构:
根本不要包装任何东西。我的意思是你不必抛出任何东西只是因为第三个库这样做。您可以捕获该异常并处理它,或返回错误代码,或者适当地更改状态。还有许多其他的可能性,而不是总是重新抛出。
您不必为所有第三方例外进行一对一翻译。如果您在内部使用库AAA,那么您可以使用单个AAAException来表示来自该库的许多异常。
有价值的知道:总是通过const引用捕获异常:
catch (const exception & ex)
这个主题非常大,我希望我的回答有助于理解它。
评论的答案:
如果我没有将第三方例外映射到我自己的API(不一定是一对一),它们会泄漏到客户端代码 - 不,他们没有,那就是整点!你必须在你的库中捕获它们,然后决定如何处理catched异常:抛出你自己的异常,返回错误代码,通知客户端监听器,记录错误等......
try {
3rdpatry.call();
} catch (const 3rdpartyException & ex) {
// throw YourException(ex.what());
// listener.notify(some_error)
// return some_code
}
通过const引用捕获并不是为了防止切片。这里有很好的discussion解释了这一点。
答案 2 :(得分:2)
对于较大的应用程序,顶级捕获通常是不够的。当你可以对它做些什么时,你需要捕获异常,但主要只有几种方法可以处理异常: