1

所以我对前缀运算符感到非常头疼。

在我在 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 循环中没有发生递增。当我对数组进行索引时,它发生在循环内的实际代码中。我认为这是一个聪明的小优化,但它使它在发布版本中不起作用。

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

4

2 回答 2

6

你的 for 循环体包括:

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

这是undefined unspecified undefined [1] 行为,因为这两个参数可以按任意顺序(甚至同时)进行评估,因此不清楚newPointIndex在第一次使用之前是否会增加。

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

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

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

[1]:阅读关于 un{specified, defined} 讨论的评论。tl;博士:神圣的跳跃蜥蜴,蝙蝠侠!

于 2013-01-25T16:43:06.757 回答
5

问题实际上在这里:

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

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

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

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

同样相关的是 1.9/15:

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

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

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

于 2013-01-25T16:43:25.447 回答