C++が面白い

最近自分の中でC++が面白くなってきた。これまでC言語Javaは普通に使えるけどC++はなんだかよく分からない変態的な言語という印象だったのが、ここに来てなんとなくコツをつかんだ感じ。一番大きかったのはコンストラクタまわりの仕組みを意識できるようになったことかな。

例えばC言語Java

int x;
FILE * fp;

とか

Integer i;
JButton button;

とか書いた場合、単なる変数の宣言でしかないんだけど、C++

CTest test;

と書くと、デフォルトコンストラクタの呼び出しが発生する。しかもメンバ変数の初期化にも同様にコンストラクタが呼び出されるので、極端な話

CTest test;

と書いただけで裏側でものすごい数のメソッドが呼ばれている可能性もある。何気なく変数に代入するコードを書けば代入演算子が呼ばれるし、コンテナに追加すればコピーコンストラクタが呼ばれる。そもそも関数呼び出しで(参照ではなく)実体を渡しただけでもコピーコンストラクタが呼ばれているというのもなかなか気付きにくい点だろう。
Javaでこの辺を意識しないでいいのはJavaのオブジェクトが全て参照(ポインタ)だからで、それに対してC++の場合は参照とポインタと実体の3種類の変数を使い分けないといけないというのは確実に混乱の原因になっていると思う。もちろんこれにはちゃんとした理由があって、Javaが全ての変数を参照としているのはガベージコレクションがあるからだし、ガベージコレクションのないC++でしかも性能を気にするなら極力スタック上に変数の実体を置きたいというのは理解できる。
C言語では動的にメモリを確保する場合は平気でmalloc/freeを使っていた(というか使わざるを得なかった)のだけど、最近のC++では生のnew/deleteは使わないようにするのが良いコーディングスタイルとされているみたい。じゃあどうするかというと、RAIIとかスマートポインタとか、要するにリソースを所有するオブジェクトを用意してそのオブジェクトの寿命に応じてリソースの確保と解放を行うようにする。それに関係して、C++では例外安全ということが(執拗なまでに)強く意識されている。リソースの解放をデストラクタで行うようにするのだから、例外が起きても確実にデストラクタが呼ばれるかどうかというのは当然重要な問題なんだけど、それにしても度が過ぎてるという気はする。

まとめると、

  • C言語コンパイラは基本型の範囲しか面倒見てくれないのでそれ以外はポインタを使ってプログラマがメモリ管理をする
  • Java言語:変数はすべて参照型、newしたオブジェクトは使われなくなったらいずれガベージコレクションで回収される
  • C++:変数は実体でも参照でもポインタでもよい、オブジェクトの確保はスタックでもヒープでもよい、ヒープに確保した場合は解放するのはプログラマの責任になるので極力スタックを使って自動的に解放されるようにする

C++というのは、正しく使うためにはコンパイラが裏でやっていることを理解する必要のある言語だと思う。だから理解できると楽しいんだけど、考えてみるとこれってかなり異常だ。よくこんな言語が流行ったよなあ。みんな絶対騙されてるって。いくらC言語に似ていてもこれはC言語とは別物なんだよ。

最後にこれまで読んだC++の本の中から参考になったものを挙げておく。それにしても、C++使ってない割に意外と読んでたんだなあ。

C++ Coding Standards―101のルール、ガイドライン、ベストプラクティス (C++ in‐depth series) Exceptional C++ Style―40のクイズ形式によるプログラム問題と解法=スタイル編 (C++ in‐Depth Series) Effective STL―STLを効果的に使いこなす50の鉄則 Modern C++ Design―ジェネリック・プログラミングおよびデザイン・パターンを利用するための究極のテンプレート活用術 (C++ In‐Depth Series)

以下は読みかけだったりはるか昔に読んで内容を忘れているもの。どれも良書だと思う。

Exceptional C++―47のクイズ形式によるプログラム問題と解法 (C++ in‐Depth Series) Effective C++ 原著第3版 (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES) More Effective C++―最新35のプログラミング技法 (ASCII Addison Wesley Programming Series)