次の短いC++プログラムをg++ -g -O1
などでコンパイルしてみると、非常に時間がかかります。最適化レベルは、-O0
以外のどの最適化でも発生します。
struct Int { int n; Int() : n(0) {} }; struct Array { Int data[8000]; Array() : data{} {} } arr;
特にテンプレートを使っているわけでもないのに、なぜこんなに遅くなるのでしょうか。
これは、Int
のユーザー定義コンストラクタがインライン展開され、それぞれにデバッグ情報をつけて回っているのが原因のようです。実際、-c
オプションでオブジェクトファイルを生成し、objdump
コマンドで中身を確認してみると、大量のデバッグ情報が埋め込まれていることが分かります。
この問題を防ぐには、以下のいずれかを実行すればよいです。
- 最適化を掛けないでコンパイルする
-g
をつけないでコンパイルするg++
ではなくclang++
を使ってコンパイルする- 生配列を用いる(明示的に初期化してもこの問題は発生しない)
Array
のコンストラクタで明示的に初期化しないでデフォルト初期化に任せる(std::array
はそうなっている。ただし、int
のような非クラス型のデフォルト初期化は「未初期化」なので注意しなければいけない)- 呼び出される
Int
のコンストラクタをデフォルトコンストラクタにする(n
を初期化するとき、ユーザー定義コンストラクタではなくデフォルトメンバ初期化を使う)
この中では、最後の手法がおすすめです。特に、Array
をテンプレート化し、int
のような非クラス型を受け取ったとしても未初期化にならないようにしたい、という場合はこの方法を使うしかなさそうです。