C++ を使う上では常識なのかもしれませんが、この無知めにどうかご教授ください。
クラスメンバを初期化する際、すべてのメンバをコンストラクタ初期化子で初期化して
いる例をよく見かけますが、なぜ、すべてをここで初期化するのでしょうか?
参照はここでしか初期化できません。
メンバにクラスを持つ場合、ここで初期化しないと、一旦デフォルトコンストラクタが
走るので効率が落ちます。
メンバクラスの初期化に必要なメンバがあるならば、メンバクラスに先立って初期化し
なければならないので、それもここですることになるでしょう。
それはわかります。
しかし、そうでない場合…
メンバクラスの初期化に必要ない組み込み型(int とか。POD 型って言うんでしたっ
け?)まで、コンストラクタ初期化子で初期化する必要はあるのでしょうか?
厳密に言えば、コンストラクタの本体で行うのは初期化ではなく代入なのでしょう。
でも、組み込み型では初期化でも代入でもパフォーマンスに差は無いのではないでしょ
うか。
繰り返しになりますが…
なぜ、すべてをここで初期化するのでしょうか?
パフォーマンスに差がないのであれば、
よりシンプルなルールの方が良いと思いますが。。
#当方C++暦6ヶ月。
シンプルな、というのは
コンストラクタ初期化子とコンストラクタ本体という2ヶ所で初期化するよりは、
1ヶ所にまとめたほうがわかりやすい、ということでしょうか。
個人的には、あまりコンストラクタ初期化子が膨れ上がるのも格好悪く見えるので、
組み込み型は本体で初期化しようかと思うのですが。
以前、どこかの掲示板で、「自分でテンプレートクラスを書くようになると、なぜコン
ストラクタ初期化子を使うのかわかるようになりますよ」という書き込みを見た記憶が
あるのですが…
テンプレートとどう関係してくるのかな…
#C++ 暦2年とちょっと。でもまだまだわからないことだらけ。
ついでに。
PC も高性能化が進み、パフォーマンスより可読性重視という風潮があると思います。
パフォーマンスに劇的な差が無いのなら、メンバクラスもコンストラクタ本体で初期化
してしまおうかな、と思うこともあります。
コンストラクタ初期化子があまり長くなるのも、読みにくくなると思いますので。
コンストラクタ初期化子で初期化するのは参照と基底クラスだけ。
これなら、コンストラクタ初期化子に書く項目はそう多くはなりませんから。
俺、なんか間違ってますか…?
>なぜ、すべてをここで初期化するのでしょうか?
コンストラクタで例外発生時、それのthrow前に
コンストラクタ初期化子に書かれた事を確実に実行してくれるからです。
コンストラクタ本体に 全ての初期化コードを書いた場合、
例外発生位置によって、初期化コードの実行が全うされないんです。
だからより初期化確実性の高いコンストラクタ初期化子でやります。
> コンストラクタで例外発生時、それのthrow前に
> コンストラクタ初期化子に書かれた事を確実に実行してくれるからです。
説得力に欠けるように思えます。
例外が発生したのなら結局はコンストラクトが失敗、
すなわちそのインスタンスは使い物にならないのだから、
初期化コードの実行が確実であることがそんなに重要なのでしょうか?
さらにいえば、初期化子で書かれたことを実行中に例外が発生したら?
> コンストラクタ初期化子で初期化するのは参照と基底クラスだけ。
追加:
- const なメンバ
- デフォルト・コンストラクタを持たないメンバ
- 初期化/代入がコスト高なメンバ
> PC も高性能化が進み、パフォーマンスより可読性重視という風潮があると思います。
可読性重視というのは、つまり、意味を明確にするということだと思います。
初期化子でしか初期化できない、あるいは、明らかに代入のコストが高いメンバなどは
当然として、「データメンバの初期化」という意味を明確にするという観点からも、初
期化子を使うことには意味があると考えます(必ずそうしているかというと、そうでも
ありませんが)。
>説得力に欠けるように思えます。
で、あんたの意見はどうなの?
難癖つけて終わり?
> で、あんたの意見はどうなの?
初期化子で初期化したほうがいいものはそうする。
PODなど、大差ないものはどっちだっていい。
僕はなるべく初期化子でやる。好みだから。
で、あんたの意見はどうなの?
>で、あんたの意見はどうなの?
俺の負けだよ。あんたの言うとおりだよ。
お前、いちいちカンに触る言い方するよな。何とかなんねぇのか?
だったら答えんでええがな。技術があっても素行がそれじゃあなあ...。
Cマガの連載も本性で書けよ。普段、掲示板で使ってる言葉遣いでよ。
>>επιστημη さん
> さらにいえば、初期化子で書かれたことを実行中に例外が発生したら?
cppll のログを拝見したことがあります。
それを catch できるのは確か、function-try block でしたか。
VC++.NET 2003 では仕様通りの動作をしたものの、まだまだ 2002 や 6.0 も現役である
今、function-try block の使用は少々忌避されるところであります。
> - const なメンバ
> - デフォルト・コンストラクタを持たないメンバ
> - 初期化/代入がコスト高なメンバ
成程、それらもありますな。
ただ、上の2つはどうにもならないとしても、最後の1つは、それがどれほどの負担に
なるかどうかを考える必要があると思います。
どの程度の基準を以って「コスト高」と呼ぶかは人それぞれだと思いますが、クラスは
すべてコスト高だなどとは思いたくありません。
>>monkey さん
確かに「初期化子」と名前がついている以上、初期化はそこですべきだという意見も妥
当のように思えます。
ではコンストラクタの意味は何かと考えると、それはオブジェクトの構築であります。
オブジェクトの構築とは何かと言うと、その大部分がデータメンバの初期化ではありま
すまいか?
コンストラクタの目的のほとんどがデータメンバの初期化であるならば、そのうち、処
理が必要ないものだけを初期化子に書くのはおかしい気もします(書かざるを得ない場
合を除く)。
初期化子でしかできない初期化もある。本体でしかできない初期化もある。では、どち
らでもできるのはどちらですべきかと言うと…続く。
また、初期化子はコンストラクタにしかないものです。C でも、C 系列の他の言語で
も、C++ のコンストラクタ以外の部分でも、基本形は全て
return-type function( arguments )
{
statements;
}
です。
直感的に見て、この基本形を破る初期化子はイレギュラーな気がしてなりません(コン
ストラクタ自体がある程度のイレギュラーではありますが)。
関数本体に書けないから、仕方なくあんな書き方をするのだという気がします。
初期化子ばかりずらずらと長くなって、コンストラクタ本体にほとんどコードが無いよ
うな書き方は読みにくいと、個人的には思います。
続き…故に、コンストラクタでも初期化子でもできる初期化は本体ですべきであると、
こう思う次第であります。
もちろん、個人的に思うだけであって、monkey さんが、初期化子のほうがわかりやすい
とおっしゃるのであれば、それを止める権利は俺にはありません。
むぅ、推敲してる間になにやら不穏なことに…
> PODなど、大差ないものはどっちだっていい。
> 僕はなるべく初期化子でやる。好みだから。
好み…その程度の理由ですか。いえ、悪く言っているのではなく。
では、初期化はすべて初期化子ですべきだという確固たる根拠があるわけではないと?
それならば、俺も安心して、自分の好みに従って本体に書くことができます。
そうではなく、何か初期化子に書かねばならない理由があるのではないかと不安で…
私も初期化子でできる限り初期化します。
テンプレートとの関係ですが、
メンバの型がテンプレートになっているときは
a = xxx;
とかかれているとき、そのコストが『わからない』
ということではないかと思います。
私は組み込み型と、そうでない型との扱いの差異は
できる限りなくしたいと思っているので、
初期化子で書かなければならない型がひとつでもある以上、
『初期化子なら統一される』
という意味で、すべてを初期化子で書きます。
やっぱり、好みの問題ですが。
コンストラクタは極力'軽く'が信条です。
なぜなら派生したときに積み重ねられるから。
それもあって、なるべく初期化子で。
# ところであたしゃ聖人君子じゃないから裏も表もありますもちろん。
# よくわからんハンドルの主に暴言吐かれる筋合いはないが。