Visual Studio 2010 - 前缀运算符 C++和数组索引中的奇怪性

visual studio 2010 - Prefix Operator Strangeness in C++ and array indices

本文关键字:索引 数组 2010 Studio 前缀 C++ 运算符 Visual      更新时间:2023-10-16

所以我在前缀运算符上遇到了一个巨大的头痛。

在 Visual C++ 2010 中的调试版本中。

someArray[++index]

将正确递增数组索引,然后使用它来索引到数组中。

在我的发布版本中,它使用数组索引,然后递增它,这引起了一些巨大的麻烦。

奇怪的是我的调试构建代码实际上有一段时间是错误的,我把它写成

someArray[index++]

这将使用索引,然后递增它,但调试版本仍在递增它,然后使用该值。 直到今天早上,我才意识到自己的错误。

下面是实际代码的示例。

for(unsigned int newPointIndex = 0; newPointIndex < newEdgeList.size() - 1;) {
    m_edges.push_back(Edge(newEdgeList[newPointIndex], newEdgeList[++newPointIndex]));
}

for 循环中没有发生递增。 它发生在我索引到数组时循环内的实际代码中。 我认为这是一个聪明的小优化,但它使它在发布版本中不起作用。

我第二次索引到数组中时,它在发布版本中使用未递增的索引,但在调试版本中工作。

你的 for 循环体包括:

Edge(newEdgeList[newPointIndex], newEdgeList[++newPointIndex])

这是未定义的指定未定义 [1] 行为,因为这两个参数可以按任一顺序(甚至同时)计算,因此不清楚newPointIndex在第一次使用之前是否会增加。

调试和优化版本很可能以不同的顺序评估参数。

我建议将newPointIndex增量放在 for 语句本身中,并写在正文中:

Edge(newEdgeList[newPointIndex], newEdgeList[newPointIndex + 1])

[1]:阅读讨论未{指定,已定义}的评论。 博士:神圣的跳跃蜥蜴,蝙蝠侠!

问题实际上就在这里:

m_edges.push_back(Edge(newEdgeList[newPointIndex], newEdgeList[++newPointIndex]));

您无法判断两个表达式中的哪一个newEdgeList[newPointIndex]newEdgeList[++newPointIndex]将首先执行。

根据C++标准,不能保证它们会从左到右执行。参见 5.2.2/8:

"后缀表达式和参数表达式的计算都是未排序的彼此相对。参数表达式计算的所有副作用在输入函数之前都已排序"

同样相关的是 1.9/15:

"当调用一个函数(无论该函数是否是内联的)时,与任何参数表达式或指定被调用函数的后缀表达式相关的每个值计算和副作用都是在执行被调用函数主体中的每个表达式或语句之前排序的。[注意:与不同参数表达式相关的值计算和副作用是未排序的。

这意味着实现不仅可以在调试发布构建中对这两个表达式具有不同的执行顺序,而且理论上还可以在每次在同一程序执行中执行该语句时更改顺序,并且没有确定性的方式

解决方案包括从这些子表达式中取出增量(如另一个答案所示)。