なぜコンストラクタ初期化子を使うの?

[戻る]
シャノン 2004/07/09(金) 20:47:54
C++ を使う上では常識なのかもしれませんが、この無知めにどうかご教授ください。

クラスメンバを初期化する際、すべてのメンバをコンストラクタ初期化子で初期化して
いる例をよく見かけますが、なぜ、すべてをここで初期化するのでしょうか?

参照はここでしか初期化できません。
メンバにクラスを持つ場合、ここで初期化しないと、一旦デフォルトコンストラクタが
走るので効率が落ちます。
メンバクラスの初期化に必要なメンバがあるならば、メンバクラスに先立って初期化し
なければならないので、それもここですることになるでしょう。
それはわかります。

しかし、そうでない場合…
メンバクラスの初期化に必要ない組み込み型(int とか。POD 型って言うんでしたっ
け?)まで、コンストラクタ初期化子で初期化する必要はあるのでしょうか?
厳密に言えば、コンストラクタの本体で行うのは初期化ではなく代入なのでしょう。
でも、組み込み型では初期化でも代入でもパフォーマンスに差は無いのではないでしょ
うか。

繰り返しになりますが…
なぜ、すべてをここで初期化するのでしょうか?

ぽこ 2004/07/09(金) 22:06:04
パフォーマンスに差がないのであれば、
よりシンプルなルールの方が良いと思いますが。。

#当方C++暦6ヶ月。

シャノン 2004/07/10(土) 00:52:57
シンプルな、というのは
コンストラクタ初期化子とコンストラクタ本体という2ヶ所で初期化するよりは、
1ヶ所にまとめたほうがわかりやすい、ということでしょうか。
個人的には、あまりコンストラクタ初期化子が膨れ上がるのも格好悪く見えるので、
組み込み型は本体で初期化しようかと思うのですが。

以前、どこかの掲示板で、「自分でテンプレートクラスを書くようになると、なぜコン
ストラクタ初期化子を使うのかわかるようになりますよ」という書き込みを見た記憶が
あるのですが…
テンプレートとどう関係してくるのかな…

#C++ 暦2年とちょっと。でもまだまだわからないことだらけ。

シャノン 2004/07/10(土) 00:57:12
ついでに。
PC も高性能化が進み、パフォーマンスより可読性重視という風潮があると思います。
パフォーマンスに劇的な差が無いのなら、メンバクラスもコンストラクタ本体で初期化
してしまおうかな、と思うこともあります。
コンストラクタ初期化子があまり長くなるのも、読みにくくなると思いますので。
コンストラクタ初期化子で初期化するのは参照と基底クラスだけ。
これなら、コンストラクタ初期化子に書く項目はそう多くはなりませんから。

俺、なんか間違ってますか…?

ごみ 2004/07/10(土) 01:20:22
>なぜ、すべてをここで初期化するのでしょうか?
コンストラクタで例外発生時、それのthrow前に
コンストラクタ初期化子に書かれた事を確実に実行してくれるからです。

コンストラクタ本体に 全ての初期化コードを書いた場合、
例外発生位置によって、初期化コードの実行が全うされないんです。

だからより初期化確実性の高いコンストラクタ初期化子でやります。

επιστημη 2004/07/10(土) 01:45:31
> コンストラクタで例外発生時、それのthrow前に
> コンストラクタ初期化子に書かれた事を確実に実行してくれるからです。

説得力に欠けるように思えます。
例外が発生したのなら結局はコンストラクトが失敗、
すなわちそのインスタンスは使い物にならないのだから、
初期化コードの実行が確実であることがそんなに重要なのでしょうか?

さらにいえば、初期化子で書かれたことを実行中に例外が発生したら?

επιστημη 2004/07/10(土) 01:49:26
> コンストラクタ初期化子で初期化するのは参照と基底クラスだけ。

追加: 

- const なメンバ
- デフォルト・コンストラクタを持たないメンバ
- 初期化/代入がコスト高なメンバ

monkey 2004/07/10(土) 07:18:58
> PC も高性能化が進み、パフォーマンスより可読性重視という風潮があると思います。

可読性重視というのは、つまり、意味を明確にするということだと思います。
初期化子でしか初期化できない、あるいは、明らかに代入のコストが高いメンバなどは
当然として、「データメンバの初期化」という意味を明確にするという観点からも、初
期化子を使うことには意味があると考えます(必ずそうしているかというと、そうでも
ありませんが)。

2004/07/10(土) 12:42:43
>説得力に欠けるように思えます。
で、あんたの意見はどうなの?
難癖つけて終わり?

επιστημη 2004/07/10(土) 12:47:54
> で、あんたの意見はどうなの?

初期化子で初期化したほうがいいものはそうする。
PODなど、大差ないものはどっちだっていい。
僕はなるべく初期化子でやる。好みだから。

で、あんたの意見はどうなの?

2004/07/10(土) 12:59:28
>で、あんたの意見はどうなの?
俺の負けだよ。あんたの言うとおりだよ。

お前、いちいちカンに触る言い方するよな。何とかなんねぇのか?
だったら答えんでええがな。技術があっても素行がそれじゃあなあ...。

Cマガの連載も本性で書けよ。普段、掲示板で使ってる言葉遣いでよ。

シャノン 2004/07/10(土) 13:24:40
>>επιστημη さん
> さらにいえば、初期化子で書かれたことを実行中に例外が発生したら?
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 さんが、初期化子のほうがわかりやすい
とおっしゃるのであれば、それを止める権利は俺にはありません。

シャノン 2004/07/10(土) 13:28:22
むぅ、推敲してる間になにやら不穏なことに…

> PODなど、大差ないものはどっちだっていい。
> 僕はなるべく初期化子でやる。好みだから。
好み…その程度の理由ですか。いえ、悪く言っているのではなく。
では、初期化はすべて初期化子ですべきだという確固たる根拠があるわけではないと?
それならば、俺も安心して、自分の好みに従って本体に書くことができます。

そうではなく、何か初期化子に書かねばならない理由があるのではないかと不安で…

PAI 2004/07/10(土) 14:15:39
私も初期化子でできる限り初期化します。

テンプレートとの関係ですが、
メンバの型がテンプレートになっているときは
    a = xxx;
とかかれているとき、そのコストが『わからない』
ということではないかと思います。


私は組み込み型と、そうでない型との扱いの差異は
できる限りなくしたいと思っているので、
初期化子で書かなければならない型がひとつでもある以上、
『初期化子なら統一される』
という意味で、すべてを初期化子で書きます。

やっぱり、好みの問題ですが。

επιστημη 2004/07/10(土) 14:47:14
コンストラクタは極力'軽く'が信条です。
なぜなら派生したときに積み重ねられるから。
それもあって、なるべく初期化子で。

# ところであたしゃ聖人君子じゃないから裏も表もありますもちろん。
# よくわからんハンドルの主に暴言吐かれる筋合いはないが。

επιστημη 2004/07/10(土) 15:00:14
ああ、初期化子では困る場合がひとつあります。
初期化子では初期化の順序をコントロールできません。
必ずclass/struct内に並べたメンバ順になります。

2004/07/10(土) 19:04:05
「あ」とかいうアホへ。

お前、いちいちカンに触る言い方するよな。何とかなんねぇのか?
だったら答えんでええがな。技術がないのに素行がそれじゃあなあ...。

2004/07/11(日) 13:44:56
「い」とかいうアホへ。
行動からして、お前も大して俺と変わらんと思うが。
程度の低い者どうし仲良くやろうぜ。類は友を呼ぶってな。

シャノン 2004/07/11(日) 19:37:38
[[解決]]
>PAI さん
なるほど、言われてみればそうですね。
納得しました。

>επιστημηさん
ふむ。自分では大したことないコストだと思っていても、それを継承したクラスでは
小さなコストが積もり積もって大きくなっているかも、ということですか。
初期化の順序は…初期化子でコントロールできないならクラス宣言でコントロールすれ
ばいいだけだと思いますが。
クラスを宣言する際は、データメンバの順番まで考えなければならないというのは、結
構な落とし穴かもしれませんね。

>い さん
そーいうのに触っちゃダメダメ。

皆さん、レスありがとうございました。得心が行きました。

ボコノン教徒 2004/07/12(月) 14:32:40
コンストラクタ初期化子で初期化された変数は、ソース・ブラウザで
捕獲できないので、ここで初期化するのをやめて欲しい、と思ったりする。

2004/07/12(月) 17:51:09
VS.NET では、IDE上で、クラスのメンバー変数を追加すると
初期化子で初期化されるコードが自動挿入される。

これより、今後は初期化子で初期化という方向に流れていく
のではと思っています。(MSの方針)

isshi 2004/07/13(火) 21:37:16
もう解決しているようですが、参考まで。

Effective C++ 改訂2版の12項に
「コンストラクタでは、代入よりも初期化を使おう」
とあります。
ただし、組み込み型については例外的にコンストラクタ内での代入を
認めています。
シャノンさんがおっしゃるように、「組み込み型では初期化でも代入でも
パフォーマンスに差は無い」というのも理由のひとつのようです。
詳しくは書籍のほうをご覧ください。
(決してアスキーの回し者ではありません。。)

古いスレッドには追加発言できません。