BEN2のブログ

たまに書いています。

競プロ中にハマった C++ の取扱い注意点

更新日 : 2020-03-23

注意

自分は、競技プログラミング以外では一切 C++ を使っていません

はじめに

自分が言語仕様を正しく理解していないため、競プロ中に「何故このコードが WA なの?」がたまに発生します。
この記事では、実際に自分がハマった事例、その解決 (解決というより解消?) 方法を載せていきます。
「言語仕様を勉強しろ」なのですが、それは一旦無視します。

この記事は、気が向いたときに更新します。

vector

トラブル : 配列の各要素に 1 を加算したいのに...
#include <bits/stdc++.h>
using namespace std;

int main() {
  vector<int> A = { 1, 2, 3 };
  for (int v : A) v++;
  cout << A.at(0) << " " << A.at(1) << " " << A.at(2) << endl;
  // 2 3 4 と出るはず...
}
1 2 3

変数 v には配列の値のコピーが格納されているため、v (コピー) に変更を加えても配列の値 (オリジナル) には影響しません。

  • 対処 (その 1)
#include <bits/stdc++.h>
using namespace std;

int main() {
  vector<int> A = { 1, 2, 3 };
  for (int i = 0; i < 3; i++) A.at(i)++;
  cout << A.at(0) << " " << A.at(1) << " " << A.at(2) << endl;
}
2 3 4

配列の各要素にアクセスしています。

  • 対処 (その 2)
#include <bits/stdc++.h>
using namespace std;

int main() {
  vector<int> A = { 1, 2, 3 };
  for (int &v : A) v++;  // 参照
  cout << A.at(0) << " " << A.at(1) << " " << A.at(2) << endl;
}
2 3 4

範囲 for 文での参照については、AtCoderC++入門 APG4b2.04.参照 にて説明されています。

こんな感じで、このあとも淡々と挙げていきます。

トラブル : 配列の各要素に関数を作用させたいのに...
#include <bits/stdc++.h>
using namespace std;

// val を m で割った余りを返す (余りが負になったら m を足す)
long long mod(long long val, long long m) {
  long long res = val % m;
  if (res < 0) res += m;
  return res;
}

int main() {
  vector<int> A = { -1, 0, 1 };
  for (int i = 0; i < 3; i++) {
    mod(A.at(i), 1000000007);
  }
  cout << A.at(0) << " " << A.at(1) << " " << A.at(2) << endl;
  // 1000000006 0 1 と出るはず...
}
-1 0 1

配列の各要素に関数の返り値が格納されていません。

  • 対処
#include <bits/stdc++.h>
using namespace std;

long long mod(long long val, long long m) {
  long long res = val % m;
  if (res < 0) res += m;
  return res;
}

int main() {
  vector<int> A = { -1, 0, 1 };
  for (int i = 0; i < 3; i++) {
    A.at(i) = mod(A.at(i), 1000000007);
  }
  cout << A.at(0) << " " << A.at(1) << " " << A.at(2) << endl;
}
1000000006 0 1

配列の各要素に関数の返り値を格納しています。

関数の引数に値を渡すことについては、C++入門 APG4b1.15.関数 にて説明されています。

その他

トラブル : 演算子の優先順位
#include <bits/stdc++.h>
using namespace std;

int main() {
  int a = 1, b = 2, c = 3;
  if (a ^ b ^ c == 0) cout << "Yes" << endl;
  if (a ^ b ^ c != 0) cout << "No" << endl;
  // a ^ b ^ c は 0 だから、Yes のみ出力されるはず...
}
Yes
No

演算子の優先順位は ^ よりも == の方が高いです。a ^ b ^ (c == 0) は 3 で、a ^ b ^ (c != 0) は 2 です。

  • 対処
#include <bits/stdc++.h>
using namespace std;

int main() {
  int a = 1, b = 2, c = 3;
  if ((a ^ b ^ c) == 0) cout << "Yes" << endl;
  if ((a ^ b ^ c) != 0) cout << "No" << endl;
}
Yes

とりあえずカッコをつけます。演算子の優先順位については、C++の演算子の優先順位 - cppreference.com などで確認できます。