Entry

今日買いなおした本 - 『Effective C++』

2010年05月09日

読んでなかったらモグリだと言われるくらい有名な『Effective C++』なんですけれど,手元の Effective C++ が相当ボロボロになっていたので,買いなおすことにしました。ページがあちこち外れちゃって,読みづらくって……。

Effective C++ 原著第3版 (ADDISON-WESLEY PROFESSIONAL COMPUTING SERIES)
Effective C++ 原著第3版
posted with amazlet at 10.05.09
スコット・メイヤーズ
ピアソン・エデュケーション
売り上げランキング: 25234
おすすめ度の平均: 4.5
5 C++歴半年
5 息抜きに読みたい本
5 かなりレベルが高いテクニック集です
5 第3版
5 そうすれば、良かったんだ!

本書について云々する必要はあまりないと思うんですけれど,少しだけ紹介しておくと,本書は,C++ の文法や構文を一通り踏まえた向きが,いざプログラミングしようと思ったときに読む本です。

ここでプログラミングというのは,それなりの規模を持ったプログラムを書くことです。C++ の入門書を読んでおもちゃプログラムを書く分には,クラスの数もせいぜい10やそこらで済むはずです。多くはふたつかみっつで終わってしまう。しかし,現実の C++ のプログラムでは,クラスの数が100や1000を超えることもざらにあったりします。そして,C++ をはじめとしたオブジェクト指向プログラミング言語の真骨頂は,このような大規模開発にこそ現れるといってもいい。

どのようにすれば,こうした規模を持つプログラムを,「うまく」かつ「効率的」に構成することができるのか。本書では,実践的な見地から,網羅的にそのテクニックを紹介しています。

勘違いしちゃいけないのは,ここに挙げられているテクニックが,知恵袋的でマニアックなスーパーテクニックを扱っているのではないということ。そうではなく,本書が扱う対象は,現在の C++ プログラミングにおいて,ほとんど「定石」と呼ばれているものです。GNU g++ には,-Weffc++ という警告オプションもあるくらい(本書の方針に沿っているかをチェックしてくれる)。あなたの C++ のコードに,本書の定石に反する箇所があるとしたら,それは,よほどの理由があって自覚的に制限を破っているとみなされると考えてもいい。自覚的に定石を破っている形跡がない場合(天然の場合)は,このエントリの冒頭に挙げたように「モグリ」と呼ばれる,と。

今日本書を買いなおしたのは,C で書かれたライブラリのハンドラをどのように扱うか迷ったからです。ハンドラというのは,例えば,SQLite3 で言うなら sqlite3 や sqlite3_stmt とかいったハンドラを使いますよね。こゆもんを C++ のクラスでラップする方法について悩んでいたのでした。

どゆことかというと,こゆもんは,一応ラッパクラスですから,次のように書きますよね。

class SQLite {
public:
  SQLite() throw ();
  virtual ~SQLite() throw ();
public:
  // いろいろ
private:
  sqlite3* dbh_;
};

ハンドラをメンバに持つことになるわけで,これは定石上(カプセル化の観点から) private として宣言することになる。

しかし,実際このハンドラを外に出さなきゃいけないときがあるわけです。例えば,sqlite3* のハンドラから SQL ステートメントを作るときなんかは,外に出さなきゃいけない。これは厳しいです。つまり,アクセサとして,次のようなメンバ関数を作るべきなのか,ということです。

  sqlite3* getHandler() const throw ();

基本的なスタンスとして,C++ では,クライアントとなる関数なりクラスなりに対して性悪説をとることが多かったりします。つまり,悪さができるようなインターフェイスなりリンケージなりを作ったら,悪用されることを考える必要があるということ。悪用した方ではなく,そゆもんを作ったほうが悪い,というスタンスです。コメントで「sqlite3 オブジェクトは delete(free)しちゃいけない」と書いたとしても,できるからにはできるように書いた方が悪い,というわけです。

今悩んでいるのは,SQLite3 ではないんですけれど,状況としては同じような感じだったりします。で,どうすっぺ,ということで,ボロボロの Effective C++ を紐解いたのでした。

結局のところ,本書では,「カプセル化の制限を緩めてでも,生のハンドラを外に出さなきゃいけないときもあるんでね?」(15項,p69)ということに。まぁ,そうなんだけどね。それでいいのか……つか,そうするしかないしなぁ……。

こゆのって,かなり身近な場面でもありうる話なので,もう少し例を挙げますね。例えば,C のファイルハンドラを管理するクラスを考えます。「C++ 使ってんだから FILE* なんか使うんじゃねー」とかいった声もありそうだけれども,実際,FILE* 型を使わなきゃアクセスできないライブラリって,結構多いんです。libjpeg とか libpng とか。さらに,Windows の場合,ファイル名を Unicode(UTF-16) で指定する場合(_wfopen_s() で開く)と,マルチバイト文字列(いわゆる Shift_JIS)で指定する場合(fopen_s() で開く)場合があります。この差異も吸収したいところ。つことで,次のようなクラスを作ることになります。

class File {
public:
  File() throw ();
  virtual ~File() throw ();  // FILE* を破棄する
public:
  // fopen_s() を呼ぶ
  void open(const std::string& filename, const std::string& mode)
    throw (std::exception);
  // _wfopen_s() を呼ぶ
  void open(const std::wstring& filename, const std::wstring& mode)
    throw (std::exception);
  // 閉じる
  void close() throw ();
private:
  FILE* fp_;
};

これにしたって,実際 libjpeg のハンドラにファイルポインタを(直接)渡す必要があるわけで,結局,生のハンドラを差し出さなくちゃいけなかったりします。これはカプセル化を弱めることになるわけで,まぁ,にんともかんとも,悩ましいところだったりする。一応,Effective C++ でいいと言っているから,いいことにしておこう。

それだけでなく,本書では,それなりに C++ に触れてきた向きでもよく間違えそうな話があちこちにあります。基底クラスの関数呼び出しに,基底クラスへの static_cast を使う誤用例(27項,p124)なんて,普通に見かけて「うげっ」となることがある。恥ずかしい間違いをしないためにも,本書は要熟読です。

せっかく新調したから,あたしもまたもう一度じっくり読むことにします。

Trackback
Trackback URL:
Ads
About
Search This Site
Ads
Categories
Recent Entries
Log Archive
Syndicate This Site
Info.
クリエイティブ・コモンズ・ライセンス
Movable Type 3.36
Valid XHTML 1.1!
Valid CSS!
ブログタイムズ

© 2003-2012 AIAN