HOWTO · C++

C++ 中的前遞增 VS 後遞增運算子

本文演示瞭如何在 C++ 中使用前自增 VS 後自增

本頁內容

對於 C++ 內建的算術型別變數,++x 和 x++ 都會讓 x 加一。差別在於運算式產生的值:前置遞增會產生更新後的值,後置遞增則會產生更新前的值。請依周圍運算式需要哪個值來選擇。對於使用者自訂型別,遞增運算子的多載行為由各自的定義決定;依照慣例,它們通常會提供類似的前置與後置行為。

C++ 前置遞增與後置遞增運算的差異

對於內建的算術型別,++x 會先更新 x,再產生運算式的結果。x++ 會先產生舊值,並在這個運算過程中完成遞增。無論哪種形式,變數都只會改變一次。多載運算子可能有不同細節,但依照慣例通常遵循相同的前置與後置差異。

執行以下範例:

#include <iostream>

int main() {
    int value = 4;
    int previous = value++;
    int current = ++value;

    std::cout << previous << ' ' << current << ' ' << value << '\n';
}
4 6 6

previous 取得第一次遞增前的值;current 取得第二次遞增後的值,這也是 value 的最終值。

在迴圈主體中,遞增運算子的位置會改變主體印出的值。第一個迴圈以 i++ 作為列印運算式:它會印出目前的值,然後遞增 i。第二個迴圈則會先執行 ++j,再執行列印運算式,因此主體印出的是更新後的值。

#include <iostream>

int main() {
    int i = 0;
    while (i < 5) {
        std::cout << i++ << '\n';
    }
    std::cout << "final i = " << i << '\n';
}
#include <iostream>

int main() {
    int j = 0;
    while (j < 5) {
        std::cout << ++j << '\n';
    }
    std::cout << "final j = " << j << '\n';
}

第一個迴圈會依序印出 0、1、2、3 和 4,接著印出 final i = 5;第二個迴圈會依序印出 1、2、3、4 和 5,接著印出 final j = 5。兩個計數器都從 0 開始,主體各執行五次,最後的計數器值都是 5。這些範例是在迴圈主體中遞增。相較之下,若遞增運算式位於 for 迴圈的迭代運算式中,它會在主體執行後才執行。如果運算式的結果會被捨棄,將 ++k 換成 k++ 不會改變迭代序列:for (int k = 0; k < 5; ++k) 和使用 k++ 的版本都會依序走訪 0、1、2、3 和 4,最後讓 k 等於 5。輸出中的 final i 和 final j 標籤維持英文。

避免在同一個運算式中修改並讀取相同變數

不要在同一個未定序運算式中,遞增某個變數的同時又讀取該變數。例如,k++ * k 在 C++ 中具有未定義行為:對 k 的修改與另一處對 k 的讀取彼此之間沒有定序關係。因此,這個運算式的結果無法預測,也不能作為有效的範例輸出。

如果想要計算舊值與下一個值的乘積,請明確安排有順序的步驟:初始化 k,將它存入 old,遞增 k,然後計算 old * k。

分開的陳述式會先在遞增 k 前保存舊值,再將保存的值與更新後的值相乘。執行以下範例:

#include <iostream>

int main() {
    int k = 10;
    int old = k;
    ++k;
    int product = old * k;

    std::cout << product << '\n';
}
110

何時使用前置遞增或後置遞增

當運算式需要舊值時,請使用後置遞增,例如 int previous = value++;。需要更新後的值時,或運算式的值會被捨棄時,請使用前置遞增;for 迴圈的迭代運算式就是後者的例子。

若不需要舊的迭代器值,使用前置遞增是常見的慣例。使用者自訂迭代器的多載運算子依其實作而定,但依照慣例通常會比照內建型別的前置與後置差異。後置遞增可能會保留並傳回先前迭代器的副本;對於複製有成本的迭代器型別,前置遞增可以省去這項工作。這並不能證明特定程式會有可測量的速度差異:編譯器最佳化與迭代器的實作都會影響產生的運算。

結論

兩種形式都會讓變數遞增一次。前置遞增會產生更新後的值,後置遞增則會產生先前的值。請選擇能清楚表達運算式所需值的形式;對迭代器而言,若不會使用先前的迭代器值,通常可優先使用前置遞增,但不要假設它一定能提升速度。

常見問題

前置遞增與後置遞增的主要差異是什麼?

對於內建的算術型別,++x 會先更新,再產生更新後的值。x++ 會先產生先前的值,並完成遞增。多載運算子的行為由其定義決定,但依照慣例通常會提供類似的前置與後置行為。

兩種形式都能用在迴圈中嗎?

可以。在 for 迴圈的迭代運算式中,結果通常會被捨棄,因此將 ++i 換成 i++ 不會改變該迴圈的迭代序列。

在 C++ 中哪一種形式比較快?

對所有運算式和型別而言,沒有一種形式能普遍保證速度較快。對迭代器或使用者自訂型別,後置遞增可能需要建立暫時副本;最佳化則可能移除不必要的運算。請依所需的值和表達意圖的清晰度來選擇,並在提出效能主張前測量實際工作負載。

什麼時候適合使用後置遞增?

當運算式需要遞增前的值時,請使用後置遞增,例如將該值指定給另一個變數。

前置遞增與後置遞增在每種語言中的行為都相同嗎?

不一定。拼寫相似的運算子可能遵循各自語言的規則。請確認所用語言的語意;本文說明的是 C++。