C++のエラーを直して覚える
実際に出力されるメッセージを読みながら、空欄を埋めて直します。全108問。間違えた問題は翌日・3日後・7日後に自動で再出題されます。
エラー別に調べる
初級
- error: expected ',' or ';' before ... の原因と直し方文末のセミコロンを書き忘れたときに出るエラーです。エラーが指す行ではなく、その1つ前の行にセミコロンが無いことがほとんどです。
- error: expected '}' at end of input の原因と直し方波括弧{}の対応が崩れ、閉じ忘れがあるときに出るエラーです。ファイルの終わりまで読んでもブロックが閉じられないため、末尾でエラーになります。
- error: 'x' was not declared in this scope の原因と直し方宣言していない変数を使ったときに出るエラーです。多くの場合はタイプミスで、g++は似た名前の宣言済み変数があれば「did you mean 'total'?」のように候補を提案してくれます。
- error: 'cout' is not a member of 'std' の原因と直し方#include <iostream> を書き忘れたまま std::cout や std::endl を使ったときに出るエラーです。名前空間std自体は存在していても、その中身(cout)を知るにはヘッダのインクルードが必要です。
- error: 'cout' was not declared in this scope; did you mean 'std::cout'? の原因と直し方#include <iostream> はしているのに、std::を付けずにcoutやendlをそのまま使ったときに出るエラーです。C++では標準ライブラリの名前はstd名前空間の中にあり、省略するにはusing宣言が必要です。
- C++でerror: missing terminating " character が出る原因と直し方文字列リテラルの閉じクォート(")を書き忘れたときに出るエラーです。閉じ忘れた行がそのままエラー行になり、後続の行でも連鎖的にエラーが出ることがあります。
- error: invalid conversion from 'const char*' to 'char' の原因と直し方ダブルクォートで囲んだ1文字("A"など)をchar型の変数に代入しようとしたときに出るエラーです。ダブルクォートは何文字であっても文字列(const char*)を作り、char型とは互換性がありません。
- if文で = と == を取り違えたときの挙動比較のつもりで書いた if (ok = 1) が実は代入文になっているバグです。C++はこれを構文エラーとして扱わず、代入結果の値を条件として評価してしまいます。
- int同士の割り算で小数点以下が消えるバグint型同士の割り算は小数点以下を切り捨てたint型の結果になるバグです。その結果をdouble型に代入しても、切り捨てはすでに終わったあとなので元には戻りません。
- 配列の添字を1つずらしてしまうoff-by-oneバグ配列の要素数と添字の範囲を混同し、ループの開始や終了条件を1つずらしてしまうバグです。要素が抜けたり、逆に範囲外を読んでしまったりします。
- int型のゼロ除算で実行時に落ちる原因int型同士の割り算で除数が0になったときに実行時エラーで異常終了するバグです。コンパイルは正常に通り、実行して初めて発覚します。
- error: no match for 'operator>>' の原因と直し方std::cout に >> を使ったり、std::cin に << を使ったりと、ストリーム演算子の向きを取り違えたときに出るエラーです。<<は出力(送り込む)、>>は入力(受け取る)で向きが逆です。
- error: '::main' must return 'int' の原因と直し方main関数の戻り値の型をvoidにしてしまったときに出るエラーです。C++の標準では、main関数は必ずint型を返すと決められています。
- error: ISO C++ forbids comparison between pointer and integer の原因と直し方int型の変数をダブルクォートの文字列リテラル(例: "20")と== で比較しようとしたときに出るエラーです。文字列リテラルはconst char*型であり、int型とは根本的に比較できません。
中級
- error: invalid conversion from 'int*' to 'int' の原因と直し方アドレス演算子&で得たポインタを、参照や普通の変数と混同して代入しようとしたときに出るエラーです。&xはint*型であり、int型の変数にそのまま代入することはできません。
- nullptrの参照外しでSegmentation faultになる原因nullptrで初期化したポインタをそのまま参照外し(*p)して書き込もうとしたときに異常終了するバグです。コンパイルは通り、実行時にクラッシュします。
- C++でerror: assignment of read-only variable が出る原因と直し方constを付けて宣言した変数に、あとから値を代入しようとしたときに出るエラーです。constは「この変数は初期化後に変更しない」という約束をコンパイラに伝えるものです。
- 参照渡しのつもりが値渡しで変更が反映されないバグ関数の引数を値渡し(int n)で受け取っているのに、関数の中身を書き換えたつもりで呼び出し元の変数まで変わることを期待してしまうバグです。値渡しでは引数はコピーされるため、関数内での変更は呼び出し元に影響しません。
- terminate called after throwing an instance of 'std::out_of_range' の原因と直し方std::vectorの範囲外の要素に .at() でアクセスしたときに、例外std::out_of_rangeが投げられ、それを捕まえずにプログラムが終了してしまうバグです。
- error: is private within this context の原因と直し方private指定されたクラスのメンバ変数に、クラスの外から直接アクセスしようとしたときに出るエラーです。カプセル化のためにprivateメンバは外部から直接触れないようになっています。
- error: expected ';' after class definition の原因と直し方クラス定義の閉じ波括弧}の後にセミコロンを書き忘れたときに出るエラーです。C++特有の落とし穴で、if文や関数定義の}にはセミコロンは要りませんが、クラスや構造体の定義には必要です。
- error: no matching function for call to 'Class::Class()' の原因と直し方引数ありのコンストラクタだけを自分で定義したクラスに対して、引数なしでインスタンスを作ろうとしたときに出るエラーです。
- error: call of overloaded '...' is ambiguous の原因と直し方同じ名前の関数が複数のオーバーロードを持ち、渡した引数の型からどちらを呼ぶべきかコンパイラが一意に決められないときに出るエラーです。
- switch文でbreakを忘れて後続のcaseまで実行されるバグswitch文の各case節末尾にbreakを書き忘れ、該当したcase以降のすべての節が続けて実行されてしまうバグです。
- 配列と、先頭要素へのポインタでsizeofの結果が変わってしまう理由配列そのもの(nums)と、先頭要素のアドレス(&nums[0])を混同してsizeofに渡してしまうバグです。見た目は似ていますが、前者は配列全体のバイト数、後者はポインタ1個分のサイズを返します。
- undefined reference to 'Class::member' の原因と直し方(staticメンバ変数)クラス内でstaticメンバ変数を宣言しただけで、クラスの外側での実体定義を書き忘れたときにリンクの段階で出るエラーです。コンパイル自体は通りますが、実行ファイルを作る最後のリンク工程で失敗します。
- 範囲for文で要素をコピーしてしまい変更が反映されないバグfor (int n : nums) のように範囲for文の変数を値(コピー)で受け取っているため、ループの中でnを書き換えても元のvectorの要素は変わらないバグです。
上級
- free(): double free detected の原因と直し方(C++のdelete)newで確保したメモリに対してdeleteを2回呼んでしまったときに出る実行時エラーです。メモリ管理システムが不整合を検知してプロセスを強制終了させます。
- new[]とdeleteの不一致が「たまたま動いてしまう」危険性new[]で確保した配列に対して、delete[]ではなく単体用のdeleteを使ってしまう不一致です。未定義動作であるにもかかわらず、int型のような単純な配列ではクラッシュせずに動いてしまうことがあります。
- ローカル変数への参照を返すとSegmentation faultになる原因関数のローカル変数への参照を関数の外に返してしまうバグです。関数を抜けた時点でローカル変数の実体は破棄されるため、返された参照は存在しないメモリを指すことになります。
- delete後のポインタ使用が「たまたま動いてしまう」危険性deleteした直後の同じポインタを使って読み書きしてしまうバグです。未定義動作であるにもかかわらず、解放直後のメモリはすぐには再利用されないことが多く、正しい値が読めてしまうことがあります。
- 仮想デストラクタが無いと派生クラスのデストラクタが呼ばれない理由基底クラスのポインタ経由で派生クラスのオブジェクトをdeleteしたとき、基底クラスのデストラクタが仮想(virtual)でないと、派生クラス側のデストラクタが呼ばれないバグです。
- 派生クラスを値渡しすると情報が失われるオブジェクトスライシング派生クラスのオブジェクトを基底クラス型の変数に値としてコピーすると、派生クラス独自の部分が切り捨てられ、仮想関数の呼び出しも基底クラスのものになってしまうバグです。
- vectorの要素をループ中に削除するとイテレータが無効化されるバグstd::vectorの要素をfor文の中でeraseしながら、そのままイテレータをインクリメントし続けてしまうバグです。eraseは削除した位置以降の要素を前に詰めるため、単純な++itでは次の要素を読み飛ばしてしまいます。
- error: no matching function for call to '...'(テンプレートの型推論失敗)の原因と直し方テンプレート関数の2つの引数に異なる型を渡したときに出るエラーです。同じ型パラメータTを2箇所で使うテンプレートは、呼び出し時にすべての箇所で矛盾なく同じ型が推論できなければコンパイルできません。
- terminate called after throwing an instance of '...' の原因と直し方throwで投げた例外をどこのtry-catchでも捕まえられず、プログラム全体が異常終了してしまうバグです。C++のランタイムはstd::terminateを呼び出し、プロセスを強制終了させます。