有时您需要在某些非严重错误条件下跳过方法的一部分执行。您可以为此使用异常,但是通常在正常应用程序逻辑中不建议仅将异常用于异常情况。
所以我做了这样的把戏:
do
{
bool isGood = true;
.... some code
if(!isGood)
break;
.... some more code
if(!isGood)
break;
.... some more code
} while(false);
..... some other code, which has to be executed.
我使用一个“假”循环,该循环将运行一次,并且可以通过中断或继续中止该循环。
我的一些同事不喜欢这样,他们称其为“坏习惯”。我个人觉得这种方法很漂亮。但是你觉得呢?
最佳答案
坏习惯,这取决于。
我在这段代码中看到的是一种非常有创意的方式,可以用较少的硫磺味关键字编写“goto”。
此代码有多种选择,根据情况的不同,它们可能更好,也可能更好。
您的解决方案
如果您有很多代码,则您的解决方案很有趣,但是将在某些有限的点上评估此处理的“退出”:
do
{
bool isError = false ;
/* some code, perhaps setting isError to true */
if(isError) break ;
/* some code, perhaps setting isError to true */
if(isError) break ;
/* some code, perhaps setting isError to true */
}
while(false) ;
// some other code
问题是您不能轻易使用“if(isError)break;”。是一个循环,因为它只会退出内部循环,而不是您的do/while块。当然,如果失败是在另一个函数内部,则该函数必须返回某种错误代码,并且您的代码一定不要忘记正确地解释错误代码。
我不会讨论使用ifs甚至嵌套ifs的替代方案,因为经过一番思考,我发现它们对于您的问题而言比您自己的解决方案差。
将goto称为... goto
也许您应该在桌上清楚地表明您正在使用goto,并记录选择此解决方案的原因。
至少,它将显示代码可能有问题,并提示审阅者验证或使您的解决方案无效。
您仍然必须打开一个块,并且不要使用goto来破坏它。
{
// etc.
if(/*some failure condition*/) goto MY_EXIT ;
// etc.
while(/* etc.*/)
{
// etc.
for(/* etc.*/)
{
// etc.
if(/*some failure condition*/) goto MY_EXIT ;
// etc.
}
// etc.
if(/*some failure condition*/) goto MY_EXIT ;
// etc.
}
// etc.
}
MY_EXIT:
// some other code
这样,当您通过goto退出该块时,就无法绕过goto来绕过某些对象构造函数(C++禁止)。此问题解决了退出嵌套循环问题的过程(并且使用goto退出嵌套循环是B. Stroustrup提供的有效使用goto的示例),但是它无法解决某些函数调用可能失败并被忽略的事实(因为有人未能正确测试其返回码(如果有))。
当然,现在,您可以从多个点,从多个循环嵌套深度退出流程,因此如果有问题...
试着抓
如果代码不应该失败(因此失败是异常(exception)的),或者即使代码结构可能失败,但是退出的过程过于复杂,则以下方法可能更清晰:
try
{
// All your code
// You can throw the moment something fails
// Note that you can call functions, use reccursion,
// have multiple loops, etc. it won't change
// anything: If you want to exit the process,
// then throw a MyExitProcessException exception.
if(/* etc. */)
{
// etc.
while(/* etc.*/)
{
// etc.
for(/* etc.*/)
{
// etc.
if(/*some failure condition*/) throw MyExitProcessException() ;
// etc.
}
// etc.
callSomeFunction() ;
// the function will throw if the condition is met
// so no need to test a return code
// etc.
}
// etc.
}
// etc.
}
catch(const MyExitProcessException & e)
{
// To avoid catching other exceptions, you should
// define a "MyExitProcessException" exception
}
// some other code
如果上面的代码中或上面的代码调用的某些函数中的某些条件不满足,则抛出异常。这比“执行/同时执行”解决方案要重一些,但是具有相同的优点,甚至可以从内部循环或内部调用的函数中止处理。
讨论区
您的需求似乎来自以下事实:您可以执行一个复杂的过程(代码,函数调用,循环等),但是您想在某些情况下中断它(可能是失败,或者是因为它比异常(exception)情况更早获得成功) 。如果可以用其他方式重写它,则应该这样做。但是也许,别无他法。
让我们假设。
如果可以使用try/catch进行编码,请执行:要中断一段复杂的代码,抛出异常是正确的解决方案(可以低估可以在异常对象内添加失败/成功信息的事实) 。之后,您将获得更清晰的代码。
现在,如果您遇到了速度瓶颈,那么解决抛出异常作为退出的问题并不是最快的方法。
没有人能否认您的解决方案是荣耀的goto。不会有goto-spaghetti代码,因为do/while不会让您这样做,但这仍然是语义上的goto。这可能是某些人可能会发现此代码“错误”的原因:他们闻到goto却没有清楚地找到其关键字。
仅在这种情况下(并且在这种情况下,此性能是经过配置文件验证的),您的解决方案似乎还可以,并且比使用if的替代方法更好),但是其质量(IMHO)比goto解决方案要低,它至少不会隐藏自身错误循环之后。
结论
就我而言,我发现您的解决方案很有创意,但我会坚持使用抛出的异常解决方案。
因此,按优先顺序:
关于c++ - 您认为 “BAD”这种技术吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/243967/