在for循环中重新排序测试条件:编译器错误?

时间:2014-01-23 08:37:22

标签: c++ visual-c++

我有一个存储在数组中的树,我正在尝试找到一个特定的节点:

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。 (调试模式,无优化)。

对我而言,这看起来像代码生成错误,但我至少在十年内没有看到过这样的错误。这是简单的未经优化的代码。当然,即使重新排列,在node测试之前实际上并未使用index,并且在x86上使用这样的越界指针并不是非常不安全,但是MSVC的{{1}正确地断言那个非法索引。

干净的构建并再次检查组件;它是可重复的。树也不是空的,总是有一个根节点。

我是否忽略了某些内容,或者这是一个严重的编译错误?

5 个答案:

答案 0 :(得分:6)

如果您有这样的for循环:

for (init; cond; step) { body; }

然后这是表达式/语句的执行顺序:

  1. 初始化
  2. COND;停止虚假,否则
  3. 步骤
  4. COND;停止虚假,否则
  5. 步骤
  6. ...
  7. 换句话说,它是这个的同义词:

    {
      init;
      while (cond) {
        body;
        step;
      }
    }
    

    在您的情况下, body 可能会index设置为sentinel。然后,您希望 cond 执行并中断循环,但请注意,在每次 body 执行之后,步骤 cond之前执行。这意味着node = &nodes[index]确实会被执行,新值为index,即sentinel。所以VS正在产生应有的东西。

    你的循环似乎与传统的for循环完全不同;我认为将它变成一个明确的while循环会更有意义。如果我正在对您的代码进行代码审查,我肯定会要求。

答案 1 :(得分:3)

您的代码重写为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);

答案 2 :(得分:2)

&#34;选择&#34;不是破碎的。 ; - )

了解循环的执行方式。

  1. 初始化Node* node = &nodes[index]

  2. 检查索引index != sentinel。出口?

  3. 循环体。这会更改index

  4. node = &nodes[index]

  5. 返回2.

  6. 在第3步index == -1之后,您将在步骤4中获得超出范围的权限。

答案 3 :(得分:1)

for (init; check; step) { body }表达式中,顺序为initcheck,然后不断重复周期bodystep,{{1所以check在检查之前发生。

但是,你的循环在这里很奇怪,因为你不需要需要 step参与体外活动!

您可以轻松地将其重写为:

node

这不仅更短,而且涉及变量的范围更紧密:)

答案 4 :(得分:-1)

可能有一个错误(如果作者不想要这种行为)与sentinel:unsigned short不能为-1; 它应该简短......或签名