一个'for'循环似乎实际上是无限的

Mic*_*ock 82 c++

我正在调试一些代码,我遇到过这一行:

for (std::size_t j = M; j <= M; --j)
Run Code Online (Sandbox Code Playgroud)

(由我的老板写的,谁在度假.)

这看起来很奇怪.

它有什么作用?对我来说,它看起来像一个无限循环.

Bat*_*eba 68

std::size_t由C++标准保证是一种unsigned类型.如果unsigned从0 递减一个类型,标准会保证这样做的结果是该类型的最大值.

该环绕值始终大于或等于M1,因此循环终止.

因此,j <= M当应用于unsigned类型时,可以方便地说"将循环运行为零然后停止".

比如运行j一个比你想要的更大的替代品,甚至使用幻灯片操作符都 for (std::size_t j = M + 1; j --> 0; ){存在,虽然需要更多的输入,但这可以说更清晰.我猜一个缺点(除了它在第一次检查时产生的令人眼花缭乱的效果)是它没有很好地移植到没有无符号类型的语言,例如Java.

另请注意,您的老板选择的方案"借用"了unsigned集合中的可能值:在这种情况下,M设置为std::numeric_limits<std::size_t>::max()不具有正确行为的情况也是如此.实际上,在这种情况下,循环是无限的.(这是你正在观察的吗?)你应该在代码中插入一个注释,甚至可能在该特定条件下断言.


1M不是std::numeric_limits<std::size_t>::max().

  • 不要把它称为"幻灯片操作员".在C++中没有这样的运算符,它只是一个看起来很聪明的混淆. (51认同)
  • @DimitarMirchev:因为它不是运营商.它是两个运算符,具有奇数间距.如果你坚持要求受访者提出不相关的问题(但理想情况下,问他们如何实现功能而不是询问"聪明"的语法),就称之为成语. (26认同)
  • 我在责怪天气. (7认同)
  • 如果M是`std :: numeric_limits <std :: size_t> :: max()`那么`M + 1`将为零,而`for(std :: size_t j = M + 1; j - > 0 ;)`循环根本不会循环. (3认同)

pax*_*blo 27

你的老板可能试图做的是M从零开始倒计时,对每个数字执行一些操作.

不幸的是,有一个边缘情况,确实会给你一个无限循环,一个Msize_t你可以拥有的最大值.而且,虽然很好地定义了无符号值在从零递减时会做什么,但我认为代码本身就是一个草率思维的例子,特别是因为有一个完全可行的解决方案而没有你的老板的缺点.

更安全的变体(在我看来更可读,同时仍然保持严格的范围限制),将是:

{
    std::size_t j = M;
    do {
        doSomethingWith(j);
    } while (j-- != 0);
}
Run Code Online (Sandbox Code Playgroud)

举例来说,请参阅以下代码:

#include <iostream>
#include <cstdint>
#include <climits>
int main (void) {
    uint32_t quant = 0;
    unsigned short us = USHRT_MAX;
    std::cout << "Starting at " << us;
    do {
        quant++;
    } while (us-- != 0);
    std::cout << ", we would loop " << quant << " times.\n";
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这与a基本相同unsigned short,你可以看到它处理一个值:

Starting at 65535, we would loop 65536 times.
Run Code Online (Sandbox Code Playgroud)

do..while上面的代码替换上面代码中的循环将导致无限循环.试试看,看看:

for (unsigned int us2 = us; us2 <= us; --us2) {
    quant++;
}
Run Code Online (Sandbox Code Playgroud)

  • 现在,边缘情况为"0".为什么不`for(size_t j = M; j--!= 0;)`? (7认同)
  • @Logic等人,在我提供的方法中没有边缘情况,我添加了代码来展示这一点.使用***解决方案,初始值"M == 0"将导致元素0未被处理,因此它*具有边缘情况.使用我的post-check`do..while`方法完全消除了边缘情况.如果你用'M == 1`来尝试它,你会看到它同时执行1*和*0.同样,用`max_size_t`(无论发生什么)开始它,它会在那个时候成功启动然后减少低至零. (7认同)