初期化されていないオブジェクトの値を読み出そうとすると未定義な動作になってしまいます。
そこで、使う前に必ず初期化されている事が重要になってくるのですが、規定の初期化ルール(いつ、どんな順番で初期化が行われるか)はあまりにも複雑なので単純に使う前に必ず初期化するようにするのがよいそうです。
だんだん文章でメモを残す事も難しくなってきたので要点を箇条書きにする事にしました。
意味がわからないときには Effective C++ を読み直すという事で(^^;)
- 初期化と代入は違う。混同しないように!
- C++ではコンストラクタ本体の実行前にデータメンバの初期化が行われる。
- 初期化子が書かれていなければデフォルトコンストラクタが自動的に呼ばれる。
- このためコンストラクタ内で代入している場合、データメンバはデフォルトコンストラクタで初期化後にコピー代入演算子が呼ばれる事になる。
- 当然、初期化子によりコピーコンストラクタが1回呼び出されるだけの方が効率がよい。
- 初期化は基底クラス→派生クラスの順に行われる。
- 初期化子で全てのデータメンバを宣言順に初期化するようにしよう。
- 明示的に初期化しなくても自動的に初期化されてしまうのだから意識できるように明示した方がよい。
- 初期化子による初期化はデータメンバの宣言順に行われる。初期化子がその順になっていなくてもWarningすら出ないが、宣言順にそろえた方がよい。
- ローカルでない静的オブジェクトの初期化には注意が必要。
- ローカルでない静的オブジェクトとはグローバルなオブジェクト、名前空間をスコープとするオブジェクト、クラス内でstatic宣言されたオブジェクト、ファイル内でstatic宣言されたオブジェクトの事
- 関数内でstatic宣言された変数はローカルな静的オブジェクト
- 翻訳単位とは1つのオブジェクトファイルを作るためのソースコードの事
- 「異なる翻訳単位で定義されたローカルでない静的オブジェクト」の初期化順はどうなるかわからない。当たり前ですが…
ちなみに同じ翻訳単位の場合は記述がありませんでしたのでわかりません。多分決まっているのでしょうが、それによらないコードを書くべき何でしょう。きっと。 - ローカルでない静的オブジェクト初期化のために別の翻訳単位にあるローカルでない静的オブジェクトを使用していると初期化が行われないかもしれない。
- 関数に対するstaticなオブジェクト(ローカルな静的オブジェクト)は、その関数の呼び出しで、制御が最初にその定義に達したときに、初期化される。
- この性質を利用して、ローカルでない静的オブジェクトは singleton に似た実装で static 関数で取得するようにすればよい。実体はその関数内で static なオブジェクトとして定義する。(singletonと違ってそのクラスのインスタンスが唯一である事を保証するわけではない)
- 使う側では常にこの関数経由でインスタンスを取得するようにする
- 全てのローカルでない静的オブジェクトをこのように置き換えれば初期化順は必要な順になるため考えなくてもよくなる。ただしデッドロックしないように!!
- この方法はスレッドセーフではない!!スレッドが1つだけのうちに全てのstaticオブジェクトを初期化しておく解決方法もある。他の方法はここでは記述がない。
と、まあこんなところです。
C++って難しいですねぇ…
0 件のコメント:
コメントを投稿