C++ パフォーマンス戦略

【 評価    】★★★☆☆

【 難易度 】★★★☆☆

【 ISBN    】4-89471-355-1

C/C++の最適化に的を絞った本は多々ありますが、理論だけではなく実測を元に分析しています。例を挙げるとインラインアセンブラを利用してみる、ビット演算に代えてみる、if…elseとswitch、iostreamとcstdioを比較検討などを行います。

しかし、実際にはswitchはジャンプテーブルが使われるから早くなるという話だけを知っていればいい(※1)ですし、iostreamとcstudioの比較に至っては安全性が同じで無い事から比較する表を作る事自体オカシイ。その他、コンパイラ依存だろ、これは?と思われる話も多いです。

実測値に基づいた本としては「Efficient C++(※2)」より劣りますが、その分最適化の初心者に対して読みやすい本だと思います。

買ってまで読む価値があるかどうかは、各々の判断に任せます。

※1 連続するif…else文をちゃんとジャンプテーブルに変換するコンパイラもあるはずです。

※2 "C++ In Depth"シリーズの一冊です(ISBN 4-89471-245-8)。RVO、仮想関数、インライン、STLと一通り網羅した上で実測値に基づいた考察を行っています。私的には結構オススメですが、安全なコードを書けるようになってから読むべきだと思います。

.NET&Windowsプログラマのためのデバックテクニック徹底解説

【 評価    】★★★★★Amazonレビュー

【 難易度 】★★★★☆

【 ISBN    】4-89100-352-9

MSDN Magazineで連載のBugSlayerを元にした本です。日本で出ているデバックの本は殆ど目を通した位、マニアな私ですが、この本だけは別格と思っています。

彼のコードはデバッカが要らない為のコーディングに重きを置く防御的プログラミングを採用しています。カスタマイズされたASSERT文はその極みとも言えるでしょう。

自作のデバッカまで紹介されており、そのソースコードが公開されているのも必見です。

本書で使用される用語とその機能はVisual C++中心ですが、理解すれば「gdb」でも「windbg」でも「OllyDbg」でも応用が利く、という点で本質をついているといえます。

私が技術書を一冊だけ無人島にもっていけるとしたら、この本を選びます。

Visual C++ .NET 実践講座 vol.1 基礎編

【 評価    】★☆☆☆☆

【 難易度 】★★☆☆☆

【 ISBN    】4-89100-283-2

3年前ほどに買ったのですが、偉く後悔した本です。現時点でも「C++」の.NET拡張ともいえる「Managed C++」の本は多くありません。「MC++」を勉強したてだったので、何かの参考になればと中身を見ずに購入。

まず、狙っている購読者層が分かりません。初心者向けの本と思いきや、CやC++を理解している人間には馬鹿らしく、何も知らない人には難しすぎます。

加えて中身の無い「授業的なサンプル」と「マウスやキーボード操作を含めて紙面を稼ぐ(softbank形式)」あたりが泣けてきます。技術的に難しい所は適度に誤魔化し、どうでも良いところだけ細かい。

コードを真似していたら動いた、こんな感じで喜べる人にはお勧めできない事もないかもしれません。

C++ Coding Standards

【 評価    】★★★★★Amazonレビュー

【 難易度 】★★★★☆

【 ISBN    】4-89471-686-0

C++をそろそろ極めたかなと思っている人にお勧めです。101の原則ルールを元に、例外を追加した事で極めて実践的なコードが書けます。

個人的に一押しなルールは以下の3つ。

■実行時エラーよりもコンパイル時エラーとリンク時エラーを歓迎しよう

■基本クラスのデストラクタはpublic仮想かprotected非仮想にしよう

■デストラクタ、リソース解放、およびswapは決して失敗させない

swapを何故失敗させないかは、過去の著書である「Exceptional C++」で紹介されている「swapイディオム」を利用するためです。何ソレ?とおもった方はその部分だけでも読んでみてください。

ルールを読み返していくうちに、極めたと思ったC++が、自分の勘違いであることが確認されてしまう悲しい本でもあります・・・。

定数の末尾

最近、定数の後にLをつけろいったら何ソレといわれました。

C++の規約では整数はint、少数はdoubleになります。末尾に特別なアルファベットをつけるとそれを変更することが出来ます。

符号無し 0U

LONG型  0L

FLOAT型 1.0F

他もあると思いますが、一般的にはこのくらいかと。



(05/12/08) doubleについて抜けていたのを追記。

適切なcast

「キャストをしてみたらコンパイルが通った」などという話を聞きます。

私の前でこんな事を言うと、駄目プログラマのレッテルがアロンアルファでくっつきます。キャストに関わるTipsを少し。

■ 絶対にC++形式のキャストを使う

具体的にはstatic_cast, dynamic_cast, const_cast, reinterpret_castです。C++形式のキャストはC形式のキャストに比べて非常に安全です。当然、人のソースと接続するために、どうしてもキャストしなければならない場合だけ利用します。

詳しくはMSDNの記事、「Deep C++」の「static_cast」あたりから読むと良いと思います。

私のオススメはconst_castです。コイツはconstを付けたり消したりする事しか出来ない。Cのキャストに慣れた方は、制約されたキャストを使用する事から始めましょう。

■ C++のoperatorを理解する

C++の組込型(int, double等)以外、型が勝手に変換される(※1)なんて事はありません。例えばStringというクラスに対して「operator const char*() { return 中身; }」などと定義する事によって、利用者が意識せずともStringがchar*型に変換されているだけです。つまり、意識しないとoperatorは凄く危険(※2)です。

CStringなどをなんとなく利用して、なんとなく変換してもらってるという状況はやめましょう。型が変わっている時は再確認(※3)する。基本です。

とりあえずこの2点ですね。気づいたらまた書くかもしれません。



C++の設計者は、「C++のキャストは置換しやすく、「敢えて」打ちにくくした。本来キャストなど不要だ。」という趣旨の話をしております。

※1 暗黙の型変換はコンストラクタのみに存在します。int型なのにdouble型として初期化したりしますが、当然i余計にスタックを確保している事をお忘れ無く。一時オブジェクトと呼ばれちょっとした嫌われ者です。(興味ある人は暗黙の型変換を禁止する「explicit」も調べてみてください)

(05/11/10追記)

operatorを暗黙の型変換と呼ぶ人もいます。私は、(警告は出るが)型が違ってもコンパイルを成立させてしまうものを暗黙の型変換と呼ぶことにしてます。

※2 C++の標準ライブラリであるbasic_stringがchar*に対するoperatorを使わずに「c_str」なんて関数を定義したか、良く考えましょう。分からないうちは自分で定義してはいけません。

※3 組込型以外は必ずincludeしているヘッダにtypedef式があります。型がoperator式を持つクラスな場合、ヘッダには宣言部分が存在します。

適切なconstの使い方(2)

最近出た本である「C++ Coding Standards」を買いました。
著者は「C++ Depthシリーズ」の過去の著者二人です。素晴らしく良くできているとおもいますので是非読んでみてください。
constについての見解も再掲載されていました。
■値渡しの場合、関数宣言(※1)にconstは不要
同氏が前書いたことと若干違います。
違う点は
int Func(int nVal);
宣言し、実際は
int Func(const int nVal)
{ ・・・ }
定義する例を追加した点。
コレ、実は私もやっていました。確かに変数を弄る危険はなくなりますが・・・。
定義の一部にconstを書き忘れて、統一性が無くなる。(経験則)
コンパイラがこの2つを同等に解釈する事を知らない人も居る為、混乱を招く。(特にクラスのメンバ関数)

そうなる位なら宣言にもconstを付けて定義はコピペした方が良いと思うんですが。Grepも置換もしやすいですし。

※1 宣言と定義の区別がついていない人、結構います。ヘッダファイルに書くべき事が宣言、ソースファイルに書くべきなのが定義です。不安だったら調べなおしましょう。(最近はヘッダに実装を書かざるを得ない場合もあります。VC++もexportのサポートを切望。)

適切なconstの使い方(1)

関数の仮引数編。元ネタはExceptional C++。

■値渡しには不要で、ポインタ渡し、参照渡しには必要。

void Func(int nVal); //値渡し
void Func(const char *szStr); // ポインタ渡し
void Func(const T& cls); //参照渡し

特に異議無い。しかし、私の中では例外あり。

Win32プログラミングでバイト列を読み込む時だ。
void Func (const BYTE* pbDoc, const DWORD cbDoc);
constを対照にしておくだけ。
 
Win32APIでは「const BYTE*」を「LPBYTE」に「typedef」して利用する為、自然に見えるが、constでないとうっかり変更してしまう(呼び出し元に影響はないが)。文字列には「LPCSTR」が存在するので問題なし。