我正在调试一些代码,我遇到过这一行:
for (std::size_t j = M; j <= M; --j)
(由我的老板写的,他正在度假。)
对我来说这看起来很奇怪。
它做什么?对我来说,它看起来像一个无限循环。
答案 0 :(得分:68)
std::size_t
由C ++标准保证为unsigned
类型。如果从0减去unsigned
类型,标准会保证这样做的结果是该类型的最大值。
该环绕值始终大于或等于M
1 ,因此循环终止。
因此j <= M
应用于unsigned
类型是一种方便的方式来说&#34;将循环运行为零然后停止&#34;。
存在替代方案,例如运行j
一个比您想要的更大的内容,甚至使用幻灯片操作符 for (std::size_t j = M + 1; j --> 0; ){
,虽然需要更多输入,但可以说更清晰。我猜一个缺点(除了它在第一次检查时产生的令人眼花缭乱的效果)是它没有很好地移植到没有无符号类型的语言,例如Java。
另请注意,您的老板选择的计划&#34;借用&#34; unsigned
集合中的可能值:在这种情况下会发生M
设置为std::numeric_limits<std::size_t>::max()
的行为不正确。 事实上,在这种情况下,循环是无限的。 (这是你正在观察的吗?)你应该在代码中插入一个注释,甚至可能在那个特定条件下断言。
<小时/> 1 受
M
不std::numeric_limits<std::size_t>::max()
的限制。
答案 1 :(得分:27)
你的老板可能尝试做的事情是从M
倒计时到零,对每个号码执行一些操作。
不幸的是有一个边缘情况,确实会给你一个无限循环,M
是你可以拥有的最大size_t
值。并且,虽然它很好地定义了当你从零递减时无符号值会做什么,但我认为代码本身就是一个草率思维的例子,特别是因为那里有一个完全可行的解决方案而没有缺点。你老板的尝试。
更安全的变体(在我看来更具可读性,同时仍保持严格的范围限制),将是:
{
std::size_t j = M;
do {
doSomethingWith(j);
} while (j-- != 0);
}
举例来说,请参阅以下代码:
#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;
}
这与unsigned short
基本相同,您可以看到它处理每个单个值:
Starting at 65535, we would loop 65536 times.
用上面的代码替换上面代码中的do..while
循环将导致无限循环。试试吧,看看:
for (unsigned int us2 = us; us2 <= us; --us2) {
quant++;
}