一旦纏めます。
21世紀現在に至っても、
世の中の手続き型プログラミング言語は、
どこかしらC/C++に似た部分があります。
言い換えると、C/C++言語の反省点を踏まえて
言語設計をしていると言えます。
C/C++言語の、筆者の考える反省点は次のとおりです。
- boolean型が無い。
- 関数の戻り値として、1個しか返せない。
- 生ポインタ。
- 故にメモリ管理が手動
- (template)
- プリプロセッサ
- #include
- (例外)
- (名前空間)
- (多重継承)
そもそもの話、C言語自体設計が古いので、
現状のメモリ事情やら、ソフトウエア技術やらに即して居ません。
象徴的なのが、「きめ細かいメモリ管理」を「人間がやる」ところ。
メモリが狭いって言ったって、携帯電話でもメガの単位はあります。
キロバイト単位を節約して、8ビットCPUを絞り出していた時代とは違います。
その証拠に、イマドキのケータイアプリは、概ねJavaです。
ポインタはC/C++の歴史的魔道と言えます。
メモリ管理方法が極めて少ないので、多重ポインタで実装するしかありませんが。
その中のどこかに構造体ポインタが挟まってたらもう駄目です。
この宣言がどエラい苦労します。
もはや呪いのアイテムです。
Cの時代は、メモリ確保と、その用法が完全に無関係なので、
何バイト確保しようが、それをいくらでも逸脱できます。
故に、バッファオーバーラン等の危険が常に付きまといます。
気をつけます、って言ったって、限界があるでしょうそりゃあ。
C++では、一応class宣言があって、new/deleteが有りますが、
deleteが手動だったりしますし。
プリプロセッサは、
プログラムソースを、コンパイラに入れるまえに書き換える。
コンパイラの機能があまりにも少ない故の、魔道具です。
「構造体宣言の前半の中括弧まで」を展開するマクロとか
ソースとマクロ定義のどっちを見ても、気持ち悪そうな実装が出来ます。
「関数の宣言に、特定のナニかを付け加えるマクロ」なんかは、
オープンソース業界の、軽量言語の実装では今でも散見します。
#includeは、
関数定義を、外部ファイルからサラリと読み込む方法がないので、
ソースプログラムを書いたら、*.c/cppと*.hの一組を書くのが「お約束」で、
「ウチの関数を使いたかったら#includeしてね?」って事になってますが、
その*.hは、利用のためだけじゃなくて、本体の実装のためでもあるので、
あちこち#includeを渡り歩いています。
これがまた面倒くさい。
多重include防止の為の #ifdef とか、もう生活の知恵の極致です。
#includeの向こう側が書き換わっちゃってると、
関数の引数とか、構造体の形が変わっちゃってるかもしれないので、
全てリビルドせざるを得ません。
そのためのmakeやらmakefileやらはもちろん或る訳ですが、
仕事を増やすための仕事に絶望した!
関数の戻り値が、1個しか戻せないのは、結構あちこちでハマリます。
構造体をnewしてreturnするとかは、C++ではあまりやりたくないので
1個だけreturnして、残りは引数に、参照渡しで入れ物を貰う。
C++では、「オブジェクト指向っぽいナニカ」が出きるようになりましたが、
多重継承という呪いのアイテムも付いてきました。
仮想関数やら、オーバーライドやらは、Cの延長線上では、
関数ポインタで実装するしかないわけですが、
ネイティブコンパイラであるが故に、「関数の順番」が非常に重要です。
#コンパイルしちゃった後は、オフセットでしか参照してないらしいので。
マイクロソフトも、MFCやらOLEやらで、七転八倒した形跡があります。
#そして、やっぱり辛くて、C#を産むわけですよ。
とまあ、反省することしきりですが、
筆者がC/C++を使わなくて済んでいるのは、
(例えば)python/PHPの作者がC/C++で実装しているお陰。
ありがたいことです。