如何在不使用goto的情况下重写

How to rewrite this without the use of goto

本文关键字:goto 情况下 重写      更新时间:2023-10-16

我是C++的新手。我有以下形式的代码。我想知道如果不使用后藤,我怎么能重写它。如果我使用break来代替它,那么我仍然会在每次通过该代码时检查循环后面的If语句,即使我确实中断了,我知道这个条件会失败,那么为什么要检查它呢?我能想到的唯一解决方案是将这段代码变成一个函数,用return替换goto,并删除循环后的if条件,只留下语句。这是一个可以接受goto的地方吗?

编辑:我还应该提到,当我们找到一个相等的成员时,我离开循环的原因是因为我不需要检查对象中的其余成员,因为我已经知道我们找到的成员对于我们正在迭代的对象是唯一的,因此,如果我们继续遍历其余的迭代器,就永远不会有匹配。所以我就退出循环。

while (begIt != endIt)
    if ((*begIt).member == someObject.member){
        // Do these statements
        goto someLabel; // then goto someLabel
    }
    ++begIt;
}
if (begIt == endIt){ // We must have not found an equal member
    // So do these statements
}
someLabel: // ...

使用算法和lambda。

auto it = std::find_if(begin, end, [&](const A& a) {
    return a.member == other.member;
});
if(it != end) {
    // found
}
else {
    // not found
}
while (true)
    if (begIt == endIt){ // We must have not found an equal member
        // So do these statements
        break;
    }
    if ((*begIt).member == someObject.member){
        // Do these statements
        break;
    }
    ++begIt;
}
// someLabel: ...

我在代码中接受的唯一解决方案。(或者单独的函数。直接执行lambda是很难看的…(

但很可能你担心的是错误的事情。插入goto可能不会提高性能,因为你打算"优化掉"的是一个单一的条件(pointer==pointer(,在99.999999%的程序中可以忽略不计。因此,即使您正在编写高性能的数字代码,我也建议您在循环后使用if进行简单的中断和检查(我敢让您向我展示一些探查器输出,以证明我错了;)(

对我来说,这似乎是对goto的完全合理的使用。

你的代码中没有意大利面条式的逻辑,不要让唱反调的人给你洗脑,让你相信他们的谎言。

您的选择是将循环和随后的条件移动到它们自己的函数中,并从该函数中移动return。您可以使用lambda来使所有逻辑保持内联:

[&]() {
    while (begIt != endIt)
        if ((*begIt).member == someObject.member){
            // Do these statements
            return;
        }
        ++begIt;
    }
    if (begIt == endIt){ // We must have not found an equal member
        // So do these statements
    }
}();
// ...

无论如何,您可以使用C++的标准算法来缩短循环逻辑。

有关重构gotos的方法的讨论,请参阅Steve McConnell的文章。我同意你有少数几种情况(没有C stdlib习惯用法(比大多数入门编程教科书建议的更难重构,但并不难重构,而且这样做更好。

我同意以上更好地使用标准库的解决方案是最好的。适用于所有语言(即纯结构化编程(的标准模式是创建一个bool foundMatch = false,在找到它时设置它,并在while循环和goto标签之间签入代码。

AFAIK使用goto的想法已经沉寂了一段时间,除了在Windows批处理脚本中,当然在C++中也没有,因为我们有各种流控制魔法。这样做主要是为了提高代码的可读性,避免最终出现意大利面条式代码,这种代码有太多的goto和标签,让人眼花缭乱,更不用说维护了。如果你想跳出循环I,break命令就是你想要的。像这样:

bool not_broken;
not_broken = true;
while (begIt != endIt)
    if ((*begIt).member == someObject.member){
        // Do these statements
        not_broken=false;
        break; // quit out of while loop
    }
    ++begIt;
}
if (not_broken && begIt == endIt){ // We must have not found an equal member
    // So do these statements
}
// code continues...

我不太担心知道begIt不会等于endIt,但如果这真的让你感到困扰,那么你可以在中断之前设置一个bool,并使用逻辑和运算符&&来检查while循环是否中断。bool在if中位于第一位是很重要的,因为当bool为false时,这将导致begIt和endIt无法进行比较。