範囲for文で要素をコピーしてしまい変更が反映されないバグ
for (int n : nums) のように範囲for文の変数を値(コピー)で受け取っているため、ループの中でnを書き換えても元のvectorの要素は変わらないバグです。
なぜエラーが出ないのか
出力: 1 2 3
(エラーなし)- C++は何も報告しません。コンパイルも実行も正常に完了するためです
出力: 1 2 3- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 #include <iostream> 2 #include <vector> 3 int main() { 4 std::vector<int> nums = {1, 2, 3}; 5 for (int n : nums) { ^ 6 n *= 2; 7 } 8 for (int n : nums) std::cout << n << " "; 9 std::cout << std::endl; 10 return 0; 11 }
出力: 1 2 3期待: 2 4 6
for (int n : nums)は各要素をnという新しい変数にコピーしているだけです。nを書き換えても元のvectorの要素には影響しません。直接書き換えるにはint&で受け取ります。
直し方: int を int& にします。
広告
広告スロット(未設定)
パターン2
1 #include <iostream> 2 #include <vector> 3 int main() { 4 std::vector<int> prices = {10, 20, 30}; 5 for (int p : prices) { ^ 6 p += 5; 7 } 8 for (int p : prices) std::cout << p << " "; 9 std::cout << std::endl; 10 return 0; 11 }
出力: 10 20 30期待: 15 25 35
範囲for文はコンテナの要素を直接触っているように見えますが、値で受け取っている限りコピーへの変更にしかなりません。
直し方: int を int& にします。
パターン3
1 #include <iostream> 2 #include <vector> 3 int main() { 4 std::vector<int> scores = {5, 6, 7}; 5 for (int s : scores) { ^ 6 s = 0; 7 } 8 for (int s : scores) std::cout << s << " "; 9 std::cout << std::endl; 10 return 0; 11 }
出力: 5 6 7期待: 0 0 0
全要素をリセットしたいのにint&ではなくintで受け取ると、コピーへの代入で終わってしまい元のvectorは一切変わりません。
直し方: int を int& にします。
よくある誤解
「範囲for文はコンテナの要素を直接触っている」というのは誤解です。for (int n : nums) は各要素をnという新しい変数にコピーしているだけで、nへの変更は元の要素に影響しません。直接書き換えたいときは for (int& n : nums) のように参照で受け取る必要があります。
まとめ
範囲for文で要素をコピーしてしまい変更が反映されないバグは中級でつまずきやすい項目です。上の3パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。