参照渡しのつもりが値渡しで変更が反映されないバグ
関数の引数を値渡し(int n)で受け取っているのに、関数の中身を書き換えたつもりで呼び出し元の変数まで変わることを期待してしまうバグです。値渡しでは引数はコピーされるため、関数内での変更は呼び出し元に影響しません。
なぜエラーが出ないのか
出力: 5(変更されていない)
(エラーなし)- C++は何も報告しません。コンパイルも実行も正常に完了するためです
出力: 5(変更されていない)- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 #include <iostream> 2 void increase(int n) { ^ 3 n = n + 1; 4 } 5 int main() { 6 int count = 5; 7 increase(count); 8 std::cout << count << std::endl; 9 return 0; 10 }
出力: 5(変更されていない)期待: 6
値渡し(int n)では引数はコピーされるため、関数内でのnへの変更はcountに影響しません。呼び出し元を変更したいなら参照渡し(int&)にします。
直し方: int を int& にします。
広告
広告スロット(未設定)
パターン2
1 #include <iostream> 2 void doubleIt(int n) { ^ 3 n = n * 2; 4 } 5 int main() { 6 int x = 4; 7 doubleIt(x); 8 std::cout << x << std::endl; 9 return 0; 10 }
出力: 4(変更されていない)期待: 8
関数の中で「変数そのものを書き換えている」つもりでも、値渡しでは別の実体(コピー)を書き換えているだけです。
直し方: int を int& にします。
パターン3
1 #include <iostream> 2 void reset(int n) { ^ 3 n = 0; 4 } 5 int main() { 6 int score = 77; 7 reset(score); 8 std::cout << score << std::endl; 9 return 0; 10 }
出力: 77(変更されていない)期待: 0
呼び出し元の変数を関数から変更したいときは、引数の型を参照(&)にする必要があります。
直し方: int を int& にします。
よくある誤解
「関数に変数を渡せば、その変数そのものが渡される」というのは誤解です。値渡しでは変数の値のコピーが新しい引数として作られるだけで、呼び出し元の変数とは別の実体になります。変更を反映したいなら参照渡し(int&)が必要です。
まとめ
参照渡しのつもりが値渡しで変更が反映されないバグは中級でつまずきやすい項目です。上の3パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。