自从我开始编程以来,我被教导如果可以避免,就不要使用'goto'。然而,我遇到了一个案例,我认为goto是保持此代码清洁的最简单方法。
我的代码如下例所示:
// code within a for-loop
// ...
// ...
try{
if(!ifstream.open())
throw special_exception;
A_EXCEPTION_HANDLED:
//...
//...
}
catch(special_exception ex)
{
// trying to fix the error here
if(error_is_fixed)
goto A_EXCEPTION_HANDLED;
// else clean up and show error message
};
此示例位于嵌套循环内部,我需要确保throw之后的代码正确执行,因此我必须编写大量开销来启动迭代,再次抛出异常。 这种情况会被认为是对goto的合理使用,还是像跳出循环等那样糟糕的风格?
答案 0 :(得分:2)
我认为根据您的描述,代码可以像这样重写:
for ( /* usual stuff */ )
try{
if(!ifstream.open())
throw special_exception;
} catch (const special_exception&) {
if (/* "can't handle the truth!" */) {
// clean up & show error message
break;
}
}
// OK, continue
}
答案 1 :(得分:2)
在异常之后重试的概念并非闻所未闻(例如:Common Lisp实现了类似语言的一部分)。
但是,你真的需要例外吗?如果你(而不是库)抛出异常,并且只有一个地方被抛出(如你的例子所示),难道你不能简单地写这样的东西吗?
if(!ifstream.open()) {
// trying to fix the error here
if(!error_is_fixed) {
throw really_unrecoverable();
}
// else let it continue normally
}
如果这个逻辑经常重复,我可以看到异常的理由并用goto重试算法。但是,如果它只发生一次或两次,我会编写恢复内联的代码(可能有辅助函数)。
答案 2 :(得分:0)
使用goto
实现循环不能合理使用goto
。
要在C ++中实现循环,请使用循环结构。
关于具体案例的详细信息,请提供。
答案 3 :(得分:0)
在你给出的例子中,我认为使用goto遍历两个块确实是不好的风格。
现在使用'goto'会产生各种不受欢迎的歇斯底里,但在这种情况下,它的风格很糟糕的原因很明显:
您的代码的读者可能会合理地期望一旦调用了异常处理程序,就会发生一些非常糟糕的事情,阻止当前的代码上下文继续。 如果预期ifstream存在而不存在,则这是一种例外情况,并且保证例外。 但是,如果打开流的尝试只是一个可以合理预期会失败的测试,那么这不是一件特别的事情。在这种情况下,根本不要使用例外。 在这种情况下,表达意图的更好方式可能是这样的:
for(/* usual stuff */)
while (!ifstream.open()) {
if (!attemptRemedialAction()) {
throw really_bad_thing_happened_exception;
}
}
// do things with ifstream,
// including goto statements if they express your intent elegantly
}
// allow the outer context or the caller to deal with the exceptional case of non-recovery
答案 4 :(得分:0)
风格正是它听起来的样子。有些人喜欢一个,有些人喜欢另一个。作为开发人员,您将与许多人合作,并且必须处理他们的不同风格。
非常重要的是不要将一种风格传播到另一种风格,而是要在项目中保持风格的一致性。如果此项目使用goto
,则坚持使用,并相应地编写您的部件。因为其他开发人员会期待跳跃并且会寻找它们。
(作为旁注,有些系统在任何给定时间都只允许存在一个例外,例如Symbian和其他EPOC衍生产品,因此我们在这里看到的可能是必需品而非风格)