2010/02/16(Tue)言語の壁(C#とC++の狭間で揺れる)

はてブ数 2010/02/16 5:21 計算機な日記::ボクと計算機 つーさ

プログラム書くのに言語はそんなに問題じゃない。だってやることは一緒さ。
それはある意味正しいけど、ある意味間違いでもある。
だって、高級言語には構文だけじゃなくて「機能」が備わってる。

就活してる。会社説明会とか行く。
どこに行っても「C/C++プログラミング経験のある方」と言われる。
僕の普段使いの言語はC#なんだよなぁ。

僕はゲーム作りに、ずっとC#を使ってきた。
でも、高確率でこれからはC++を使うことになると思う。あるいはJavaかもしれない。
僕はC++も書けるけど、「STLをある程度使える」ぐらいのレベルでしかなくて、マスターしてるとは言い難いし、
Javaなんか、大学の課題でブロック崩しAppletを作っただけ。ほとんど書いたことがない。

たとえば、C#で僕が作ったゲームアプリケーションと同じコトをC++でやろうと思うとどうなるのか。
C#にはC#の流儀があって、C++にはC++の流儀があるから、1対1でトランスコードするのが必ずしも美しいわけではないけど、
C#からC++へ環境を移そうと思ったときに、今まで書いてきたコードはどうすればいいのかというのを考えてみる。
C++を日常的な言語として使うにあたって、僕が今から勉強しないといけないことは何なのか明確にする意味を込めて。

C#3.0からC++(0xじゃないやつ)に移行したときにぶつかりそうな壁リスト

.NETクラスライブラリが使えない。
まぁ、C#は.NETな言語なので、参照さえ追加すれば、今風の便利なライブラリがいっぱい使える。けど、C++ではしかるべきライブラリを導入して、それもライセンスに気をつけて使わなくちゃいけない。C#でも外部ライブラリが必要な場合は多々あるんだけど、ゲーム作りにおいては頻繁ではないかな。せいぜい、DirectXとOggVorbisぐらいか。というか、どうせフレームワークを作るのであんまり関係ない。
言語の機能としてのプロパティが使えない。
C++だと、setter, getter を使えという話。DateTime.NowはDateTime.getNow()だし、obj.X=100 は obj.setX(100) になる。あんま美しくないと思うけど、こーゆーのは、今までにどんな言語に触れてきたかで、受容可能かどうかが違うのかもしれない。たとえば、生粋のJavaerの人は、それに疑問すら抱かないのではないかなぁ。
値型と参照型
C#はclassは参照型で、structは値型。structは派生できない。C++は全部値型。すっかりC#に慣れてしまっている僕は、うっかり代入するとコピーで大変なことになる。これ、リソース管理において、非常に重要。GCのあるC#でも、ちゃんと解体しないとリソースリークを起こすらしいので、オブジェクトの解体責任の管理はしてるけど、参照をうっかりコピーしてると、アクセスしたら解体済みでした! なんてことが容易に起こる。参照は参照のまま扱いたいなぁ。
STLと参照
前述のとーり、C#ではclassは全部参照なので、ListやらDictionary<TKey, TValue>に突っ込むときもさっぱり意識しないでじゃんじゃん代入してる。C++ではその辺どうなるんだろうかと。C++じゃ、ローカル変数を宣言してvectorとかmap<TKey, TValue>に突っ込んだりするんだけど、そこで何が行われるのかを僕は知らない。直感的には、参照をキープするだけじゃうまくいかないような気がするから、内部的にはどこかにコピーされてるのかな。まずは、STLの実装について学ばなきゃいけないと思う。その点、C#はGC言語だから、必要とあらば値型変数でさえもヒープに乗っけてくれる。意識してればパフォーマンスの低下は防げるし、便利だ。実際に値のコピーを避けようと思ったら、C++ではどういう風に書く? newしてポインタを保持するしかない? 別にポインタに苦手意識はないけど。.だったり->だったりしてめんどくs
匿名メソッドが使えない。
関数ポインタは超ややこしい。まぁ、普通に考えればfunctorを使えってことだろうけど。functorのためにクラス作るのがなんか抵抗ある。匿名メソッドは使えなくなる。array.Sort( (a,b) => a - b ); なんてもってのほか。まぁ、boolなoperator<を定義してlessですか。あ、メソッドコンバインもできないかな。メソッドをコンバインするfunctorを書けばいいのかな?
foreachが使えない
for each なんて拡張構文がありましたっけ。実は使ったことないのでよく知らないのですけど。
引数を束縛したデリゲートの作り方がわからない
void Add(obj a, int b); という関数があって Add(obj, 3); 。さてここで、あるコンテナのすべての要素に3を加えたい。C# ならたとえば、list.ForEach(m=>Add(m, 3));。はて、C++では? ん、コンストラクタに3を受け取るfunctor作ればいいんすか。そうっすね……。やっぱ、めどい。なんかいい方法あるのかな。
boost
これは単純に興味がある。結構フツーに使われてるイメージがある。勉強してみたい。
演算子のオーバーロード
C# は + 演算子だけオーバーロードすればよかったのに、C++では += もオーバーロードしないといけない。めんどくさい。
linqがない
イラネ
配列が参照型じゃない
てゆか、どうせC++じゃ、全部vectorでせう。

列挙してみて、(「めどい」は多いが)案外少ないことに驚く。
僕はC#を勉強し始めたときSTLがさっぱりわけわかんなかったので、
C#のジェネリクすげー状態だったんだけど、STLもわかってしまえば(使うだけなら)なんのことはない。

参照の扱いと匿名メソッド周りがかなり大きな比重を占めてる感があるけど、
実現可能性の話で言えば、フツーにC++でもいいのかなぁという気もしてきた。
まぁ、変数名の命名規則とかメンバに付けるpre/suf-fixとか、色々と流儀も違って、
でもまぁそれはコーディング規約次第だとは思うけど、慣れるまで大変なんだろうなぁ。

ただ、計算機資源は有限だから、それが制限されてることを考えるとパフォーマンスのよいコードを書きたい。
私はまだ、 sizeof(vector) の値も知らない。
そんな私がC++をマスターできる日は来るのだろうか。

レポート書かなきゃいけないけど、モチベーションが上がらなかったのでダラダラ記事書いた。
とりあえず、レポートを書く。

留年しては元も子もない。

うん。