C++におけるオペランドの評価順序をサンプルコードで解説
プログラミング言語には、演算がどのように実行されるかを定めるルールがいくつか存在します。代表的なものとして、「演算の優先順位」「結合規則」「評価順序」が挙げられます。
結合規則とは、同じ優先順位を持つ演算子が並んだときに、左から右へ処理するのか、右から左へ処理するのかを決める規則のことです。C++の多くの二項演算子(算術演算子など)は、左から右への結合規則を持つと定義されています。
一方で注意が必要なのがオペランドの評価順序です。C++では、演算子の左右どちらのオペランドが先に評価されるかは保証されていません(未規定)。そのため、副作用を伴う関数呼び出しを一つの式に複数含めると、挙動に注意が必要です。
ここで、オペランドの評価順序を確認できるサンプルプログラムを見てみましょう。
サンプルプログラム
#include <iostream>
using namespace std;
int x = 2;
int changeVal() {
x *= x;
return x;
}
int main() {
int p = changeVal() + changeVal();
cout << "Value: " << x << endl;
cout << "Operation result: " << p << endl;
return 0;
}
実行結果
Value: 16 Operation result: 20
実行結果の解説
このプログラムでは、グローバル変数 x の初期値は 2 です。changeVal() 関数は x を二乗して返すため、処理は次のように進みます。
- 1回目の
changeVal()呼び出し:x = 2 × 2 = 4を返す - 2回目の
changeVal()呼び出し:x = 4 × 4 = 16を返す
したがって、加算の結果 p は 4 + 16 = 20 となり、最終的な x の値は 16 になります。
この実行環境では、左側のオペランドから先に評価されたことが分かります。ただし、前述のとおりC++では + 演算子のオペランド評価順序は標準規格上保証されていないため、コンパイラや最適化設定によって評価の順番が変わる可能性があります。
実務においては、副作用(x *= x; のような状態変更)を伴う関数呼び出しを一つの式に複数回含めるのは避け、文を分けて順序を明示的に記述することが推奨されます。これにより、どのコンパイラでも同じ結果が得られる、可読性の高い安全なコードになります。
-
C++による二分木の垂直順序走査
二分木が与えられたとき、そのノードの値を垂直順序で走査する問題について解説します。同じ行と列に複数のノードがある場合は、左から右の順序で出力します。 問題の例 以下のような二分木を考えます。 この木に対する垂直順序走査の結果は [[9], [3, 15], [20], [7]] となります。 アルゴリズム 水平距離(x座標)をキーとするマップ m を定義する。値はノードの値のリスト。 再帰関数 solve(node, x) を定義し、深さ優先探索でノードをマップに登録する。 ノードが null の場合は終了 左の子を x - 1 で再帰呼び出し
-
C++で実装するN分木(N-ary Tree)のレベル順走査アルゴリズム
N分木(N-ary Tree)が与えられたとき、そのノードの値をレベル順走査(Level Order Traversal)、つまり上の階層から順に同じ深さごとにまとめて取得することを考えます。N分木の入力データはレベル順走査の形式でシリアライズされており、各子ノードのグループは null 値で区切られて表現されます。例えば、下図のようなツリーは [1,null,3,2,4,null,5,6] と表されます。この場合、期待される出力は [[1],[3,2,4],[5,6]] となり、第1レベルにはルートの「1」、第2レベルには「3, 2, 4」、第3レベルには「5, 6」が含まれます。解法のアプ