pep*_*psi 33 c++ error-handling exception-handling exception
我花了几个小时阅读关于何时使用例外的SO问题,似乎有两个阵营有不同的观点:
这只是一个有争议的话题,没有被广泛接受的最佳实践吗?
Mat*_* M. 13
你可以从丰富的答案中找到答案,但肯定没有达成共识.
从语义上讲,异常和错误提供了完全相同的功能.事实上,它们在所有语义方面都是相同的,并且错误可以像异常一样被任意丰富(您不必使用简单的代码,您可以使用真正的数据包!).
唯一的区别是它们的传播方法:
另一方面:
这两种解决方案看起来很笨拙的原因很简单就是错误检查很困难.事实上,我每天写的大部分代码都涉及错误检查,无论是技术还是功能.
那么该怎么办 ?
警告:提前演示,如果您只关心答案,请跳到下一部分
我个人喜欢在这里利用类型系统.典型的例子是指针引用二分法:指针就像一个可以为null的引用(并重新设置,但这里没关系)
因此,而不是:
// Exceptions specifications are better not used in C++
// Those here are just to indicate the presence of exceptions
Object const& Container::search(Key const& key) const throw(NotFound);
Run Code Online (Sandbox Code Playgroud)
我倾向于写:
Object const* Container::search(Key const& key) const;
Run Code Online (Sandbox Code Playgroud)
或者更好的是,使用聪明的指针:
Pointer<Object const> Container::search(Key const& key) const;
template <typename O>
O* Pointer<O>::operator->() const throw(Null);
template <typename O>
O& Pointer<O>::operator*() const throw(Null);
Run Code Online (Sandbox Code Playgroud)
在这里,我发现使用异常是多余的,原因有两个:
我本身没有异常问题,但是它们会使代码变得尴尬,请考虑:
void noExceptions(Container const& c)
{
Pointer<Object const> o = c.search("my-item");
if (!o) {
o = c.search("my-other-item");
}
if (!o) { return; } // nothing to be done
// do something with o
}
Run Code Online (Sandbox Code Playgroud)
并将其与"例外"案例进行比较:
void exceptions(Container const& c)
{
Object const* p = 0;
try {
p = &c.search("my-item");
}
catch(NotFound const&) {
try {
p = &c.search("my-other-item");
}
catch(NotFound const&) {
return; // nothing to be done
}
}
// do something with p
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,使用异常似乎不合适:/
另一方面:
try {
print() << "My cute little baby " << baby.name() << " weighs " << baby.weight();
}
catch(Oupsie const&) {
// deal
}
Run Code Online (Sandbox Code Playgroud)
肯定比以下更吸引人:
if (!print("My cute little baby ")) { /*deal*/ }
if (!print(baby.name())) { /*deal*/ }
if (!print(" weighs ")) { /*deal*/ }
if (!print(baby.weight())) { /*deal*/ }
Run Code Online (Sandbox Code Playgroud)
什么是最好的呢?
这取决于.像所有工程问题一样,没有银弹,这都是关于让步的.
所以记住两件事:
如果您发现自己想知道是否使用例外,请尝试使用您的API.如果没有明确的赢家,那就是:没有理想的解决方案.
哦,当很明显在制作它时选择的错误报告机制不再合适时,不要犹豫重构你的API.不要感到羞耻:需求随时间而变化,因此API随之变化是正常的.
就个人而言,我倾向于仅对不可恢复的错误使用异常:因此我的代码中只有少量try/catch,只有在最外层,才能准确记录错误(爱堆栈帧)并记录BOM的转储.
这与Haskell非常相似(并且确实受到强烈影响),代码分为两个明确的部分:虽然任何可以抛出异常,但只有IO部分(外部部分)可能实际捕获它们.因此,纯部分必须以其他方式处理错误条件,以防它们"正常".
但是,如果我遇到一个问题,使用异常使代码更容易阅读和更自然(这是主观的)然后我使用异常:)
Bri*_*lly 10
我认为这不是C++社区独有的讨论,但这里有两个高级指南对我有所帮助:
异常比错误代码更容易使用,因为它们可以被深度嵌套的子例程抛出,并且仅在可以处理它的级别被截获.
错误代码需要向上传递,因此调用另一个函数的每个函数都必须将错误代码传递回其调用者.
错误代码与异常没有任何明显的功能优势,因为异常可以在其中捆绑错误代码.可能有一段时间错误代码可能比异常更有效,但我认为额外代码的成本和维护它的难度超过了那里的任何可能的优势.
但是,许多应用程序中存在错误代码,因为它们是在没有异常的语言中编写或移植的,因此继续使用统一的错误处理方法是有意义的.
不,没有达成共识.
编辑:正如您所看到的,从其他答案来看,没有达成共识 - 只有思想流派,设计原则和行动计划.没有任何计划完全适合所有情况.