在 for 循环中重新排序测试条件:编译器错误?
Reordering test condition in for-loop: compiler bug?
我有一个存储在数组中的树,我正在尝试找到一个特定的节点:
std::vector<Node> nodes = ...
const unsigned short sentinel = -1;
unsigned short index = 0;
for (Node* node = &nodes[index]; // root node
index != sentinel;
node = &nodes[index])
{
if (foo(*node)) {
index = node->left;
} else {
index = node->right;
}
}
换句话说,没什么特别的。但是,MSVC 2012 失败,尝试访问超出范围的nodes[sentinel]
。原来它先计算&nodes[index]
,然后测试index
。(调试模式,无优化)。
对我来说,这看起来像是一个代码生成错误,但我至少十年没有见过这样的错误。这是未经优化的纯代码。当然,即使进行了重新排列,在测试index
之前实际上并没有使用node
,并且在x86上拥有这样的越界指针并不是非常不安全,但是MSVC的vector<>
正确地断言了该非法索引。
做了一个干净的构建并再次检查了程序集;它是可重复的。树也不是空的,总有一个根节点。
我是否忽略了某些东西,或者这真的是一个严重的编译器错误?
如果你有一个这样的 for 循环:
for (init; cond; step) { body; }
那么这是表达式/语句的执行顺序:
- 初始化
- cond;在 false 上停止,否则
- 身体
- 步
- cond;在 false 上停止,否则
- 身体
- 步
- 。
换句话说,它是它的同义词:
{
init;
while (cond) {
body;
step;
}
}
在您的情况下,可能会发生身体设置index
sentinel
的情况。然后,您希望cond执行并打破循环,但请注意,在每次主体执行之后,step都会在cond之前执行。 这意味着node = &nodes[index]
确实会被执行,新值为index
,即sentinel
。所以VS正在生产它应该生产的东西。
您的循环似乎与传统的for
循环完全不同;我认为将其变成一个明确的while
循环会更有意义。如果我正在对您的代码进行代码审查,我肯定会要求这样做。
你的代码重写为 while 循环就像
Node* node = &nodes[index]; // root node
while(index != sentinel)
{
{
if (foo(*node)) {
index = node->left;
} else {
index = node->right;
}
}
node = &nodes[index];
}
最后一行可能是对节点的访问[-1]。
我把你的循环重写为
unsigned short index = 0;
do
{
Node* node = &nodes[index];
if (foo(*node)) {
index = node->left;
} else {
index = node->right;
}
} while(index != sentinel);
"select" 没有被破坏。
查看循环是如何执行的。
-
初始化
Node* node = &nodes[index]
-
检查索引
index != sentinel
。退出? -
环形体。这改变了
index
! -
node = &nodes[index]
-
回到 2.
在步骤 3index == -1
之后,您可以在步骤 4 中获得超出范围的访问权限。
在for (init; check; step) { body }
表达式中,顺序为:init
、check
,然后它不断重复循环body
、step
、check
,以便在检查之前发生step
。
然而,你的循环在这里很奇怪,因为你不需要node
参与体外!
您可以轻松地将其重写为:
const unsigned short sentinel = -1;
std::vector<Node> nodes = ...
for (unsigned short index = 0; // root node
index != sentinel;
)
{
Node& node = nodes[index];
if (foo(node)) {
index = node.left;
} else {
index = node.right;
}
}
这不仅更短,而且涉及的变量范围更窄:)
哨兵可能存在错误(如果作者不希望这种行为):无符号短不能为 -1; 它应该很短...或签名的内容
- 如何在for循环中包含两个索引值的测试条件
- 如何在多个 Catch2 测试用例中检查相同的条件
- 这个循环测试条件是什么意思?
- 如果前一个测试条件成功,则禁用测试条件
- 获取模拟开罗::上下文以测试路径上的条件
- 为什么每次迭代都由 i+6 完成,为什么这个素数测试函数的条件是 i*i<=n?
- 视窗驱动程序,旋转锁采集和条件测试
- 无法理解循环中的测试条件
- 返回语句中的条件测试
- 在 for 循环中重新排序测试条件:编译器错误?
- 为什么测试条件没有效果
- C++ - 测试是否存在 DLL 以有条件地运行某些函数
- 使用字符指针测试条件
- 使用 iStream 对象测试条件
- 是否可以将多个关系表达式放入 for 循环的测试条件中
- 具有大量相互依赖条件的单元测试代码
- 如何放置条件断点来测试CString变量是否为空
- c++在while条件下声明和测试变量
- 使用 gtest 测试构造函数内部条件的方法是什么?
- 单元测试的条件派生