我什么时候应该在括号内递减变量,什么时候应该在括号外递减变量?



当我注意到如果按以下方式实现我的函数无法正常工作时,我正在实现插入排序的版本。这个版本应该在元素被复制到新数组中时对元素进行排序,同时保持原始元素不变。

vector<int> insertionSort(vector<int>& heights) {
vector<int> expected(heights.size(), 0);
int j, key;
for(int i = 0; i < expected.size(); i++){
expected[i] = heights[i];

j = i-1;
key = expected[i];
while(j >= 0 && expected[j] > key){
expected[j+1] = expected[j--];    
}

expected[j+1] = key;

}

return expected;
}

我注意到在执行预期[j--]时,该功能无法正常工作,但是当我在括号外递减时,它工作正常。 换句话说,两者之间有什么区别

while(j >= 0 && expected[j] > key){
expected[j+1] = expected[j--];    
}

while(j >= 0 && expected[j] > key){
expected[j+1] = expected[j];
--j;
}

要回答这个问题,我们需要看看要expected[j+1] = expected[j--];的参数的计算顺序。查看 cppreference 的评估顺序页面,我们看到以下内容适用于 C++17 及更高版本:

    在每个简单的赋值表达式
  1. E1 = E2和每个复合赋值表达式E1 @= E2中,每个值计算和E2的副作用都是在每次值计算和副作用之前
  2. 排序的E1

在您的情况下,这意味着expected[j--]的每个值计算和副作用都是在开始评估expected[j+1]之前计算的。特别是,这意味着j+1将基于j在你用j--递减的值,而不是它之前的值。


在C++17之前,不确定分配操作的左侧还是右侧是先排序的。这意味着在 C++14 及更早版本中,您的代码表现出未定义的行为:

  1. 如果相对于使用同一内存位置中任何对象的值进行的值计算,则对内存位置的副作用是未排序的,则行为是未定义的。

在这种情况下,j"内存位置",并且相对于值计算j+1j--递减是未排序的。这与 cppreference 的未定义行为示例非常相似:

a[i] = i++; // undefined behavior until C++17


在代码的第二个版本中,在分配完成之前不会递减到j

最新更新