带语句的循环goto
是的!我们在这里要使用的第一种方法包括臭名昭著的声明!显然,没有与 .我希望你从未在生产代码中看到过这种情况,除非你在就业市场上工作了几十年。goto
goto
在编程的旧时代,编码循环的方式是通过标签和语句。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++的旧时光,我们仍然可以使用语句和标签。不过有几个问题。的范围完全不受限制,更糟糕的是,我们可以从函数中的其他地方转到,即使它没有意义。换句话说,它不安全,也很难推理我们程序的正确性。goto
i
LOOP
仍然没有初始化:循环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.10
v.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.while
for
#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;
}
我认为这不是一个好主意。如果你真的需要将增量与控制块解耦并使其成为有条件的,那么你的循环的目的就被破坏了,最好使用不同的结构。尽管如此,这是可能的,也许它比循环更好for
while
您甚至可以省略退出条件,您将获得无限循环。在这种情况下,您必须以不同的方式处理终止。很可能你最终不会得到一个非常惯用的解决方案。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/webdev/292550.html