C++中使用初始值设定项的语句的演变 – 第 2 部分


带语句的循环goto

是的!我们在这里要使用的第一种方法包括臭名昭著的声明!显然,没有与 .我希望你从未在生产代码中看到过这种情况,除非你在就业市场上工作了几十年。gotogoto

在编程的旧时代,编码循环的方式是通过标签和语句。goto

#include <iostream>
#include <vector>

int main () {
    std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    size_t i = 0;

    LOOP:
        std::cout << v[i] << '/n';
        ++i;
    if (i < 10) {
        goto LOOP;
    }
    return 0;
}

好吧,我们可以带回C++的旧时光,我们仍然可以使用语句和标签。不过有几个问题。的范围完全不受限制,更糟糕的是,我们可以从函数中的其他地方转到,即使它没有意义。换句话说,它不安全,也很难推理我们程序的正确性。gotoiLOOP

仍然没有初始化:循环while

关键字使循环更安全,因为可以从随机位置跳转到循环的主体,但由于您无法在其控制块中初始化变量,因此仍然无法限制循环索引的范围,除非我们接受循环和大括号之间的索引初始化。while

#include <iostream>
#include <vector>

int main () {
    std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    size_t i = 0;

    while (i < 10) {
        std::cout << v[i] << '/n';
        ++i;
    }

    return 0;
}

安全不是问题,但索引的范围不受限制。此外,我们必须注意更新循环变量,因为它不是可以在控制块中完成的事情。goto

尽管存在这些问题,但当您想要有条件地更新循环帮助程序变量时,while 循环仍然是一个很好的解决方案。例如,当您将 while 循环与迭代器一起使用时。

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    auto it = v.begin();
    while (it != v.end())
    {
        if (*it % 2 == 1) {
            // As erase() invalidates the iterator, we use its returned value
            it = v.erase(it);
        } else {
            // Otherwise, we simply increment it
            ++it;
        }
    }

    for (const auto e: v) {
        std::cout << e << ' ';
    }

    return 0;
}

But to be fair, in most cases you just want to use a standard algorithm and get rid off the problem of loops completely…

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    v.erase(std::remove_if(v.begin(), v.end(), [](auto e){return e % 2 == 1;}), v.end());

    for (const auto e: v) {
        std::cout << e << ' ';
    }

    return 0;
}

The good old loop for

For loops are the remedy for all the issues we mentioned regarding loops. In its control block, we can create the loop variable, therefore its scope is limited and it also gets updated automatically after each iteration.

#include <iostream>
#include <vector>

int main () {
    std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    for(size_t i = 0; i < 10; ++i) {
        std::cout << v[i] << '/n';
    }

    return 0;
}

What can go wrong? In the above case, we have a fixed end condition. If it wouldn't be fixed to , but instead we called , it would mean a new function call before each iteration. And don't expect the compiler to optimize it away. I mean, there is no guarantee that the size of wouldn't actually change and don't write bad code leaving it to the compiler to optimize it. So often you'll see that the end condition is fixed outside of the loop.10v.size()v

// ...
const int vectorSize = v.size();
for(size_t i = 0; i < vectorSize; ++i) {
// ...

In the above examples, we had full control blocks. But it's not even necessary to use all the different parts of the control block, you can leave out the variable initialization or the increments. In fact, you can mimic a loop with an initializer by using a loop without the update part.whilefor

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    for(auto it = v.begin(); it != v.end();)
    {
        if (*it % 2 == 1) {
            // As erase() invalidates the iterator, we use its returned value
            it = v.erase(it);
        } else {
            // Otherwise, we simply increment it
            ++it;
        }
    }

    for (const auto e: v) {
        std::cout << e << ' ';
    }

    return 0;
}

我认为这不是一个好主意。如果你真的需要将增量与控制块解耦并使其成为有条件的,那么你的循环的目的就被破坏了,最好使用不同的结构。尽管如此,这是可能的,也许它比循环更好forwhile

您甚至可以省略退出条件,您将获得无限循环。在这种情况下,您必须以不同的方式处理终止。很可能你最终不会得到一个非常惯用的解决方案。

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/webdev/292550.html

(0)
上一篇 2022年11月3日 15:40
下一篇 2022年11月3日 17:38

相关推荐

发表回复

登录后才能评论