nullptrの参照外しでSegmentation faultになる原因
nullptrで初期化したポインタをそのまま参照外し(*p)して書き込もうとしたときに異常終了するバグです。コンパイルは通り、実行時にクラッシュします。
エラーメッセージの読み方
Segmentation fault
(エラーメッセージなし)- これはプログラム自身の出力ではありません。プログラムは何も言わずに落ちています
Segmentation fault- シェルが検知した異常終了の種類 — OSが「不正なメモリアクセス」などを検出しプロセスを強制終了させました
見つけ方- このメッセージだけでは行番号すら分かりません。原因はコードを読んで特定するしかありません
このエラーが出る典型パターン
パターン1
1 #include <iostream> 2 int main() { 3 int *p = nullptr; 4 *p = 5; ^ 5 std::cout << *p << std::endl; 6 return 0; 7 }
Segmentation fault
nullptrはどのオブジェクトも指していません。そこへ書き込もうとするとOSが不正なメモリアクセスを検知してプロセスを強制終了させます。有効なint変数のアドレスをpに入れてから使う必要があります。
直し方: *p = 5; を int value = 5; p = &value; にします。
広告
広告スロット(未設定)
パターン2
1 #include <iostream> 2 int main() { 3 int *ptr = nullptr; 4 *ptr = 10; ^ 5 std::cout << *ptr << std::endl; 6 return 0; 7 }
Segmentation fault
エラーメッセージはプログラム自身の出力ではなく、シェルが検知した異常終了の種類を1行で報告しているだけです。原因はコードを読んで特定する必要があります。
直し方: *ptr = 10; を int v = 10; ptr = &v; にします。
パターン3
1 #include <iostream> 2 int main() { 3 int *data = nullptr; 4 *data = 99; ^ 5 std::cout << *data << std::endl; 6 return 0; 7 }
Segmentation fault
nullptrを「まだ何も指していない」という意味の安全な初期値として使うのは正しいですが、使う前に必ず有効なアドレスを代入する必要があります。
直し方: *data = 99; を int d = 99; data = &d; にします。
よくある誤解
「nullptrは0と同じ意味だから安全」というのは誤解です。nullptrは「どのオブジェクトも指していない」ことを表すだけで、そこへの書き込みや読み込みは有効なメモリ領域を指していないため、OSに検知されクラッシュします。
まとめ
nullptrの参照外しでSegmentation faultになる原因は中級でつまずきやすい項目です。上の3パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。