イネスさん
新人さんいらっしゃい♪ということで、初々しくも C++ を教えています。そんなとき感じるのが C++ は Java より 弱い(?) なんて空気。んー、うまく言えないのですが ニュータイプOOPL のなり損ない、みたいな捕われ方といいますか。世間一般には、旧型言語ぽいイメージなのかしら?
Java は C++ に比べて設計が綺麗で、どうでもいいことで悩まないで良く、落とし穴も少ない言語です。「C++ と Java どっちで作る?」と聞かれたら、「選べるなら Java つかっとけ」ですよね、普通。
そんな「無駄に悩ませる話」の一つ、「参照、ポインタ、値 選べる3つのタイプ」な全然うれしくないバリエーションをもつ C++ と、そんなことに頭のリソースを持っていかれない Java ・・・なんて話題。
参照が使えるときはいつでも参照を使いましょう - 神様なんて信じない僕らのために
↑のタイトルがそのまんま結論ですが、ポインタを使うことはまずなくって、引数については 参照を使いましょう、です。
戻り値については、getter のようなメンバを返すものは const & *1を、関数内で値を作って返すようなものは 値を返します。(この時、return文で直接コンストラクタを使って値を作って返すようすると、最適化されて無駄なコピーコストがかからない、ってのも重要なポイントですよ♪)
・・・なぁんて、たかが 引数渡しと戻り値 の話だけなのに、これだけの薀蓄が語れちゃう。そう、それが C++ 。
これが愉しくなりだすと、もう普通の人には戻れません(w 誰かが困っていると「説明しましょ」とニコニコしながら擦り擦り寄っていく。私は C++ が好きだー!
というわけで、「C++ と Java どっちで作る?」と聞かれたら、C++ を選んじゃうんです。(デレデレです)
余計ごと
クラスのメンバ変数を参照で持つことは、私んちはそんなにしていません。
参照でHoldするメンバがいる場合、必ずコンストラクタ初期化子で初期値を指定してあげなくてはならないのですが、私んちは、initialize(と言う名前のただのメンバ)関数で依存性注入するスタイルが多いので、Null になれないのがかえって邪魔になってしまうから。なので メンバは shared_ptr で保持ることが多いです。
でもこれはきっと私の設計ミス。Null でないことを保証してくれる参照を使った方が多分うれしい結果になるもの。だめだ、早くなんとかしないと。
追記
お風呂に入ったら酔いが冷めました。
昼間 C++ を「未完成Java」 とか、Java を 「パーフェクトC++」 とか、そんな認識されているのを目の当たりにして「なんだかなー」みたいに思って帰宅して、Isoparametric さんのエントリをみてうれしくなって「そーですよねー。偉い人にはそれがわからんのですよ♪」と浮かれてしまったようです。
で、エントリを書いているうちに、「説明しましょ♪」になって、それが愉しくって脱線、・・と。
* * *
私は、真面目に C++ を使ったのが今のプロジェクトが始めてで、だから他のOOPLでの感覚で 「OOP するなら 気軽に new 出来ないとやってられないよね」と、なんでもshared_ptr なコードをかなり書いてしまってます。これが今となっては失敗だったなぁと思うのです。、「参照は必ず初期化しなくてはならない」が非常に不便に感じた(なによー、「全部参照。ポインタ禁止」なんてできないじゃん)のですが、ようするに
・参照を受ける変数は必ず初期化されなければならない(故に、ポインタを引き回すような構造になりにくい)
という点が不自由のように見えて「セーフティ」なのがキモ。
がよく解っていなかった ....orz
また、論理デザインの依存関係についてはちゃんと考えて作ってきたのだけれど、実装デザインについては何も考えていなかったので、依存関係がメタメタです。値で持つ(Has-A)か 参照/ポインタで持つ(Holds-A)かの違いを意識していなかったのが アイタタタ、だったり。
当たり前の話ですが、値で持てば 持ち主のsizeは、持っている値のsizeに依存するので、private/public に関わらず、Has している 値の型(の詳細)に依存します。参照/ポインタでもてば、size の問題は棚上げできます。(前方宣言とあわせて実装デザインの依存を立ちきることが出来ます)
そんな風に、C++ でプログラミングする時は、自分が抽象的な事をやっている頭の片隅で酷く低レベルなものも意識していて、それが酷く鬱陶しかったり、逆に愉しかったり。
・・・ああ、やっぱり言いたいことがうまくまとまらないで、とりとめの無い話に。orz