有时您需要在某些非严重错误条件下跳过方法的一部分.您可以使用异常,但通常不建议在正常应用程序逻辑中使用异常,仅针对异常情况.
所以我做了这样的伎俩:
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.
Run Code Online (Sandbox Code Playgroud)
我使用一个"假"循环,它将运行一次,我可以通过中断或继续中止它.
我的一些同事不喜欢这样,他们称之为"不良做法".我个人觉得这个方法很漂亮.但你怎么看?
pae*_*bal 47
不好的做法,这取决于.
我在这段代码中看到的是一种非常有创意的方式,可以用较少的硫磺味关键词来写"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
Run Code Online (Sandbox Code Playgroud)
问题是你不能轻易使用"if(isError)break;" 是一个循环,因为它只会退出内循环,而不是你的do/while块.
当然,如果失败在另一个函数内部,函数必须返回某种错误代码,并且您的代码不能忘记正确解释错误代码.
我不会讨论使用ifs甚至嵌套ifs的替代方案,因为经过一些思考后,我发现它们比你自己的解决方案更差.
也许你应该清楚地说明你正在使用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
Run Code Online (Sandbox Code Playgroud)
这样,当您通过goto退出块时,您无法绕过goto(C++禁止)的某个对象构造函数.
这个问题解决了从嵌套循环问题中退出的过程(并且使用goto退出嵌套循环是B. Stroustrup给出的一个例子,作为goto的有效使用),但它不能解决一些函数调用可能失败并被忽略的事实(因为有人未能正确测试他们的返回代码,如果有的话).
当然,现在,您可以从多个循环嵌套深度退出多个点,因此如果这是一个问题......
如果代码不应该失败(因此,失败是例外),或者即使代码结构可能失败,但退出过于复杂,那么以下方法可能更清楚:
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
Run Code Online (Sandbox Code Playgroud)
如果上面代码中的某些条件或上面代码调用的某些函数内部不满足,则抛出异常.
这比do/while解决方案稍微重一些,但具有相同的优点,甚至可以从内部循环或内部调用函数中止处理.
您的需求似乎来自于您可以执行复杂的过程(代码,函数调用,循环等),但您希望在某些条件下中断它(可能是失败,或者因为它比例外更快成功) .如果你能以不同的方式重写它,你应该这样做.但也许,没有其他办法.
让我们假设一下.
如果您可以使用try/catch对其进行编码,请执行以下操作:要中断复杂的代码,抛出异常是正确的解决方案(您可以在异常对象中添加失败/成功信息这一事实不应低估).之后您将获得更清晰的代码.
现在,如果你处于一个速度瓶颈,解决你的问题抛出异常作为退出并不是最快的方法.
没有人可以否认你的解决方案是一个美化的goto.不会有goto-spaghetti代码,因为do/while不会让你这样做,但它仍然是一个语义goto.这可能是一些人可能会发现此代码"不好"的原因:他们闻到了goto而没有清楚地找到它的关键字.
在这种情况下(并且在此性能,经过分析验证的情况下),您的解决方案看起来很好,并且比使用if的替代方案更好,但质量较差(恕我直言)比goto解决方案至少不会隐藏自身假循环背后.
就我而言,我发现你的解决方案很有创意,但我会坚持抛出异常解决方案.
所以,按优先顺序排列:
Pau*_*lin 31
你几乎只是将"goto"伪装成假循环.无论你喜欢和不喜欢,你都会使用一个真正毫无掩饰的goto.
就个人而言,我只是把它写成
bool isGood = true;
.... some code
if(isGood)
{
.... some more code
}
if(isGood)
{
.... some more code
}
Run Code Online (Sandbox Code Playgroud)
g .*_*g . 24
为什么要使用假循环?你可以用一种方法做同样的事情,它可能不会被认为是一种"坏习惯",因为它更受期待.
someMethod()
{
.... some code
if(!isGood)
return;
.... some more code
if(!isGood)
return;
.... some more code
}
Run Code Online (Sandbox Code Playgroud)
Wed*_*dge 11
这是令人费解和困惑的,我会立即废弃它.
考虑这个选择:
private void DoSomething()
{
// some code
if (some condition)
{
return;
}
// some more code
if (some other condition)
{
return;
}
// yet more code
}
Run Code Online (Sandbox Code Playgroud)
还要考虑将上面的代码分解为多个方法.
public bool Method1(){ ... }
public bool Method2(){ ... }
public void DoStuff(){
bool everythingWorked = Method1() && Method2();
... stuff you want executed always ...
}
Run Code Online (Sandbox Code Playgroud)
其工作原因是由于称为短路逻辑.如果Method1返回false,则不会调用Method2.
这还有一个额外的好处,你可以将你的方法分成更小的块,这将更容易进行单元测试.
您要做的是非本地故障恢复.这goto是为了什么.用它.(实际上,这是异常处理的目的 - 但如果你不能使用它,'goto'或'setjmp/longjmp'是下一个最好的东西).
这种模式,if(succeeded(..))模式和'goto cleanup',都是3在语义上和结构上都是等价的.使用代码项目中最常见的一个.一致性很有价值.
我会提醒if(failed(..)) break;你,如果你试图嵌套循环,你会产生一个惊人的结果:
do{
bool isGood = true;
.... some code
if(!isGood)
break;
.... some more code
for(....){
if(!isGood)
break; // <-- OOPS, this will exit the 'for' loop, which
// probably isn't what the author intended
.... some more code
}
} while(false);
..... some other code, which has to be executed.
Run Code Online (Sandbox Code Playgroud)
既没有goto cleanup也if(succeeded(..))没有这个惊喜,所以我鼓励使用这两个中的一个.
基本上你刚刚描述了goto.我一直在C中使用goto.我不认为它不好,除非你用它来模拟一个循环(从来没有这样做过!).我在C中使用goto的典型用法是模拟异常(C没有例外):
// Code
if (bad_thing_happened) goto catch;
// More code
if (bad_thing_happened) goto catch;
// Even more code
finally:
// This code is executed in any case
// whether we have an exception or not,
// just like finally statement in other
// languages
return whatever;
catch:
// Code to handle bad error condition
// Make sure code tagged for finally
// is executed in any case
goto finally;
Run Code Online (Sandbox Code Playgroud)
除了catch和最后有相反顺序的事实,我不明白为什么这个代码应该是因为它使用goto,如果真正的try/catch/finally代码完全像这样工作并且不使用goto.这是没有意义的.因此,我无法确定为什么您的代码应被标记为BAD.