パターン - みる会図書館


検索対象: Modern C++ Design
63件見つかりました。

1. Modern C++ Design

XVI まえがき アーキテクチャを著しく表現力の高い , 簡潔で保守しやすいコードに対応付けることのできる高水準機能が保持 されているのです。 デザイン・パターン , ジェネリック・プログラミング , C+ + という 3 つの要素が力を合わせるわけです。こう いった要素を組み合わせることによって , 縦横の直交性を保ちながら高いレベルの再利用性を達成できるので こでの横軸とは , わずかな量のライプラリ・コードを組み合わせることによって ( これはコード自体が す。 オープン・エンドとなっていることを意味しています ) , 様々な構造や動作を実装できるということです。そし こういったコンポーネントの汎用性によってそれらが様々な分野のプログラムで適用可能となると て縦軸とは , いうことです。 本書では , オプジェクト指向開発の現場で幾度となく発生している問題に対してパワフルな解決策を提供する デザイン・パターンの力を借りています。デザイン・バターンとは , 優れた設計から蒸留して得られた部品であ り , 様々なコンテキストで発生する問題に対する健全 , かっ再利用可能な解決策のレシピなのです。デザイン・ バターンは , 設計情報を伝達するための示唆に富んだ用語集を提供することにも注力しています。そしてデザイ ン・パターンは , 問題 , そして時間をかけて作り上げられてきた様々な解決策 , さらにそれぞれの解決策を選択 した場合の結果を解説したものでもあります。プログラミング言語がいくら進化しても , デザイン・パターンで しか表現できないものが存在するのです。そして , ある種のデザイン・パターンに従って , 本書で解説している コンポーネントを組み合わせることにより , より大きな具体的な問題に取り組めるようになるのです。 ジェネリック・プログラミングとは , 機能的要求が狭い範囲に限定されている型の抽象化を行った上で , その 要求に対するアルゴリズムを実装するというパラダイムです。アルゴリズムを定義する際 , 演算を行う型に対し て厳格で狭い範囲に限定されたインタフェースを定義することになりますが , 同じアルゴリズムは様々な幅広い 型に対して用いることができるはずなのです。本書での実装は , 特殊性を最小化し , 極めて簡潔ながら高い効率 を達成し , 手作業による注意深いコード化にも対抗できるよう , ジェネリック・プログラミング・テクニックを 用いています。 本書で使用している実装用のツールは C+ + だけです。本書中には , お洒落なウインドウ・システム , 複雑な ネットワーク・ライプラリ , 巧妙なロギング・メカニズムといったコードはありません。その代わり , 上記全て を , そしてそれ以上のものを容易に実装できる基本的なコンポーネントについて解説しています。このような コンポーネントの実装を支援する幅広い機能が , 0 + には用意されているのです。 C+ + は , C のメモリ・モデル を基づいているため C と同程度のパフォーマンスが期待でき , そしてポリモフィズムのサポートによってオプ ジェクト指向テクニックが利用でき , さらにテンプレートによってコード・ジェネレータとして驚くべき性能を 発揮するのです。テンプレートは , ユーザとライプラリの密接な連携を可能にするため , 本書中の全てのコード にはテンプレートが数多く用いられています。ライプラリのユーザは , ライプラリの制約に従いながら , 文字通 りコード生成を制御できるのです。ジェネリック・コンポーネント・ライプラリの役割は , 指定されたユーザ型 とその動作をジェネリック・コンポーネントに取り込み , 健全な設計とすることなのです。こういったテクニッ クは静的な性質を持っているため , 適切なパーツの混合や適合で発生するエラーを , たいていの場合 , コンパイ ル時に捕捉することができます。 本書では , 柔軟 , 多機能 , 使用が容易な実装済み設計パーツ , すなわちジェネリック・コンポーネントの生成 方法を解説しています。ジェネリック・コンポーネントは , フレームワークの形態を採っていません。実際 , そ のアプローチは正反対であり , フレームワークが特定のオプジェクト・モデルを採用するために独立したクラス を定義している反面 , ジェネリック・コンポーネントはお互いが独立した軽量の設計成果物を自由に混合 , 適合 できるようにしています。これはフレームワークを実装する上でも利用できるのです。

2. Modern C++ Design

5.1 Command デザイン・パター CIient Oke 「 Receiver Act i on ( ) 107 Command Execute ( ) ConcreteCommand state . Execute ( ) 図 5 ユ Command デザイン・パターン ある動作を実行したい場合に , オプジェクト , そのメンバ関数 , そしてメンバ関数への引数を呼び出しとして組 2 つ目として , タイミングという観点で Command パターンを見てみましよう。通常のプログラミングでは , いったことが , 互いの関連をいっさい切り離した状態で実現できるのです。 オプジェクト群に対して様々な受信側オプジェクトを差し替えて使用できるということを意味しています。こう み立てることになります。例えば : window. Resize(), 0 , 200 , 100 ) ; / / ウインドウのリサイズ そして , 呼び出しの要素 ( オプジェクト , 手順 , 引数 ) を組み立てる時と , 実際の呼び出しを行う時は , 概念的 に同じタイミングで発生するのです。しかし Command パターンの場合 , 起動側に呼び出しの要素が揃ってい る状態で , 呼び出しを無期限に延期できるのです。つまり , Command パターンによって , 以下の例のような遅 延呼び出しが可能になります : Command resizeCmd( window , &Window: :Resize , 0 , 0 , 200 , 100 ) ; / / 後で resizeCmd. Execute ( ) ; / / オブジェクト / / メンバ関数 / / 引数 / / ウインドウのリサイズ ( あまり見かけない , &Window::Resize という C+ + の構造については後ほど詳述します。 ) Cornmand2S ターン では , 処理を実行するために必要な環境を揃えるタイミングが , 処理を実行するタイミングと異なっています。 2 つのタイミングの間で , プログラムはオプジェクトとしての処理要求を格納し , その引き渡しを行うわけです。 タイミングに関連する要求が無い場合には , Command パターンは必要ないでしよう。こういった観点から見た 場合 , c 。皿 a れ d オプジェクトの存在意義はタイミングにあると言っても良いくらいなのです。後で処理を行う必 要があるからこそ , その時まで要求を保持しておくオプジェクトができるわけです。 こういった点から Command パターンにおける 2 つの重要な特徴を導き出すことができます : ・インタフェースの分離 : 起動側と受信側は隔離されます。 ・タイミングの分離 . command は , 後で開始できる処理要求をいつでも開始できる形で保存します。

3. Modern C++ Design

索引 if, 252 , 281 , 321 if-else, 32 , 281 , 282 , 284 スマート・ポインタ アドレス演算子どー , 181 ー 182 暗黙の変換とーー , 182 ー 184 工ラー報告とーー , 192 ー 194 書き出し時コピー (COW) と一 , 175 ー 176 ーー型の暗黙の変換 , 182 ー 184 参照カウント方式と・一 , 176 ー 178 , 197 ー 198 参照追跡方式と一 , 198-199 参照リンク方式とーー , 178 ー 179 順序比較演算子と一 , 190 ー 192 チェックの問題と一 , 192 一 194 ディープ・コピーとーー 174 ー 175 等価性と一 , 184 ー 189 生の一一 , 182 ー 184 195-199 マルチスレッドし一 非等価性と一 , 184 ー 189 破壊型コピーと一 , 179 ー 181 194 ー 195 配列と一 ーーのまとめ , 207 ー 208 の所有権取り扱い戦略 , 173 ー 181 ーの基本的解説 , 167 ー 208 何でもやっちゃえインタフェースの失敗と一 , 4 ー 5 対称性 , 288 ー 291 対称型マルチプロセッサ , 157 ファンクタどー , 105 - ーのロック , 323 ー 325 何でもやっちゃえインタフェースの失敗と一 , 4 ー 5 セマンティックス セマフォ , 326 対数時間のダブル・ディスパッチャ , 277 , 291 ー 301 , 314 ー 316 - ーに対するコンパイル時のアルゴリズム操作 , 82 長さの算出と - , 57 ー 58 基本的な型と一の検出 , 45 ー 46 タイプリスト , 234 , 282 , 283 , 287 対数ダブル・ディスパッチャ , 277 , 291 ー 301 , 314 ー 316 メモリの - ー , 87 ー 94 チャンク チェックの問題 , 192 ー 194 タブルの生成 , 76 ダブル・ディスパッチ , 277 , 280 - ースライシング , 317 タイム ーの分離 , 107 タイミング ーを用いたクラス生成 , - ーへの連結 , 62 ー 63 ーのまとめ , 81 ーの部分的な並べ替え , ーの必要性 , 53 ー 55 ーーの定義 , 55 ー 56 ーの生成 , 57 ーの検索 , 60 ー 61 ーの基本的解説 , 53 ー 81 70 ー 79 67 ー 70 直交性のあるポリシー , 21 抽象的成果物 , 220 ー 227 , 229-230 , 234 , 242 335 109 ディープ・コピー , 131 , 174 ー 175 , 200 定数 ツール・メニュー DoubIe-Checked Locking パターン , 155 ー 158 Command パターン , 105 ー 110 Abstract Factory パターン , 53 ー 55 , 76 , 231 ー 247 ノヾターン バインド , 122 , 124 , 127 , 129 , 132 ー 135 配列 , 20 ー 22 , 194 ー 195 入出金 , 322 何でもやっちゃえインタフェースの失敗 , 4 ー 5 生のポインタ型への暗黙の変換 , 182-184 名前の循環依存 , 257 トランポリン関数 ( サンク ) , 295 ー 300 独自バウンシング仮想関数 , 253 統計情報 , 250 同期化オプジェクト , 319 等価性 , 184 ー 189 「天変地異効果」 , 180 テンプレート化された演算子 , 187 ーーを用いたポリシー・クラスの実装 , 12 ーの利点 , 6 ー 8 ーの部分的な特殊化 , 57-58 テンプレート・パラメータ , 10 ー 12 , 70 —Functor クラスの一一スケルトン , 110 ー 115 テンプレート 転送関数のコスト , 130 ー 131 デフォルトの自由領域アロケータ , 84 デストラクタ , 13 ー 14 Strategy パターン , 8 Prototype パターン , 240 ー 244 DoubIe-Checked Locking パターン , 155 ー 158 Command パターン , 105 ー 110 Abstract Factory パターン , 53 ー 55 , 76 , 231 ー 236 デザイン・パターン 整数 - ーの型へのマッピング , 31 ー 34 Prototype パターン , 240 ー 244 Strategy パターン , 8 バタフライ割り当て , 92-94 パラメータ 最適化されたー型 , 46 ー 47 テンプレートーー , 10 ー 12 , 70 , 112 バルク割り当て , 92 , 93 , 95 ハンドル , 171 汎用のファンクタ , →ファンクタ Command デザイン・パターンとーー 現実世界の問題と一 , 130 ー 133 チェイニング要求と一 , 129 ー 130 - の基本的解説 , 105 ー 136 ・一の取り扱い , 116 ー 119 ・一のまとめ , 134 ー 136 バインドと一 , 126 ー 129 ヒープ割り当てと一 , 131 ー 133 引数の型変換と一 , 121 ー 122 戻り型の変換と一 , 121 ー 122 106 ー 108 ーを用いたアンドウとリドウの実装 , 133

4. Modern C++ Design

本書推薦の言葉 氏を指しています。 位田真一 , 吉田和樹訳 , ソフトバンク刊 ) の著者である Erich Gamma 氏 , Richard Helm 氏 , Ralph Johnson 氏 , John VIissides 0 の ec な 0 e れ t 記 Software (Addison-Wesley, 1995 : 邦訳は「オプジェクト指向における再利用のためのデザイン・パターン」本 * 3 "GoF ”とは "Gang of Four ” ( 4 人組 ) の略であり , デザイン・パターンに関する良書 Design Patterns: EIements 可月 e 社 sa 尻 e なっています。 (JohnVIissides 氏 ) によって , 彼の成果に基づく共同執筆コラムが 2 つ , 0 + e で書き著されるまでに A Ⅱ drei の意向が明らかになった時点で , コミュニテイからの異議は撤回され , 今では Andrei と GOF の 1 人 起こりました。しかし , パターン自身をコード化するのではなく , パターンの実装を自動的に生成させるという してはいけないという基本的な見解を持っているデザイン・パターンのコミュニティとちょっとしたいざこざが を , テンプレートによって実装することを提案しています。この提案をきっかけに パターンをコード中に表現 この延長線として , Andrei は良く使用される言語イディオムとデザイン・パターン , 特に GoF * 3 のパターン トについて考察しています。 ) 用されているのです。 (Andrei は , 本書中で CTAssert をさらに洗練させた Compi1eTimeChecker テンプレー テンプレート・コードは , あなたにとって新鮮なものかもしれません。実際に , 今までとは異なった考え方で使 るもの」が「存在しているもの」と同じくらい重要なのです。「ソースコード」の一部分がわざと省略されている 特殊化がなされ , false に対する特殊化がなされていない点にもご注意下さい。この設計においては「欠けてい たったこれだけです。汎用テンプレート CTAsse て t が定義されていない点にご注意下さい。また t て ue に対する template く > struct CTAssert く true> { } ; template く C001> struct CTAssert ; ンプレートという , コンパイル時に評価を行うことができる assert マクロです : 私が彼の成果を人々に紹介する際に用いている最も簡潔な例の 1 つを紹介しましよう。これは CTAssert テ ンプレートでできることをどのように実現するのかに対して私に深い感銘をもたらしてくれたのです。 テンプレートで何ができるのかということに対して私に衝撃を与えてくれました。しかし Andrei の成果は , テ はテンプレートに対する認識をさらに改めることになったのです。 Barton 氏 , Nackman 氏 , Stepanov 氏は , 1998 年になって , 私は A Ⅱ dreiAlexandrescu 氏と電子メールによるやり取りを始めました。ほどなくして私 Barton 氏 , Nackman 氏 , Stepanov 氏やその他の人達が既に示していたのです。 ベルであり , そういった使用方法はテンプレートが持つ可能性の一面を撫でただけのものであるということを 一体何が書けるというのでしようか ? テンプレートに関する当時の私の理解は , まだ T のコンテナというレ このため私は M 。刃ガéct 加 eC+ + でも , テンプレートに関してほとんど言及しないことにしたのです。私に ないのです。 る上 , Barton 氏と Nackman 氏のもたらした成果と同様に , テンプレートについての知識をほとんど必要とし ことができ , ライプラリの利用者は基底クラスから継承したり何らかの仮想関数を再定義することなく拡張でき ジェクトのように ) 動作し , コンテナやアルゴリズムは関数ポインタや関数オプジェクトを同じものとして扱う せず , また , アルゴリズムはコンテナのことをいっさい関知せず , イテレータはポインタのように ( しかもオプ Stepanov 氏によるライプラリ設計はエレガントなものでした : コンテナはアルゴリズムのことをいっさい関知 2 つ目の理由は , その後しばらくして , STL について色々と調べる機会があった時の話になります。 Alexander 私は目から鱗が落ちる思いでした。 れらはいずれも型を表していない ( ! ) ことが判るはずです。こういったテンプレートの使用法を提示されて ,

5. Modern C++ Design

まえがき 対象読者 XVII 本書の対象読者は , 大きく分けると 2 つのカテゴリに分かれます。最初のカテゴリは , 0 + プログラマ経験者 で最新のライプラリ作成テクニックをマスターしたいと考えている方々です。本書では , 不可能とも思えるよう な能力を含んだ , 驚くほどパワフルかつ新しい 0 + のイディオムを解説しています。こういったイディオムは高 レベルのライプラリを作成する際に利用することができます。また中級の C+ + プログラマで , もう一歩ステッ プ・アップを望んでいる方々も , ほんの少し努力するだけで , 本書は手放せないものとなるでしよう。少し難解 な 0 + コードがいくつか出てきますが , それらは全て本書中で解説しています。 2 番目のカテゴリは , 忙しいプログラマで手つ取り早く作業を済ませてしまう必要がある方々です。こういっ た方々は , 実装上の込み入った詳細のほとんどを斜め読みして , 提供されているライプラリの使用方法に集中す ることができます。各章は , 導入となる解説から始まり , まとめのセクションで終わっています。プログラマの 方々は , コンポーネントを理解し , 使用するためにこういった部分をリファレンスとして使用することができる でしよう。これらのコンポーネントは , 個別に理解することができ , 非常にパワフルながら , 安全に楽しく使用 できるものです。 本書を読み進めるには , 0 + によるプログラミング経験と向上心が必要です。また , テンプレート , および標 準テンプレートライプラリ (STL) に慣れ親しんでいれば理解しやすいかもしれません。 デザイン・パターン (Gamma 他 1995) に関する知識も推奨されますが , 必須ではありません。本書で扱って いるパターンとイディオムについては , 詳細に解説しています。しかし , 本書はパターンの書籍ではないため , 完全に一般化された形でパターンを扱おうとはしていません。パターンはライプラリ開発者側の実践的な観点に よって表現されているため , 主にパターンに対してのみ興味を持っている方々も違った視点で本書を読み進める ことができるでしよう。 Loki 本書では , Loki という実在する 0 + ライプラリを解説しています。 Loki は北欧神話における機転の利 くいたずら好きな神の名前であり , ライプラリの独創性と柔軟性から北欧の茶目っ気ある神様を読者 の方々に思い浮かべていただけることを意図して付けたものです。ライプラリにおける全ての要素は , Loki というネームスペースに格納されています。本書中のコーディング例では , インデントが深くなり , またコードのサイズも大きくなるため , ネームスペースを割愛しています。 Loki は無償で利用可能で , http://www.awl.C0m/CSeⅡg/tit1eS/0ー201ー70431ー5 からダウンロードすることができます。 Loki は , スレッド部分を除けば 0 + 規格に則って記述されています。これは , 悲しいことに現在の多くのコ ンパイラでは , スレッド部分の対応を行わなければならないことを意味しています。私は Loki の実装とテスト を Windows 上の Metrowerks の CodeWarrior pro 6.0 と Comeau C + + 4.2.38 を用いて行いました。おそらく KAI C+ + でもこのコードで問題無いはずです。べンダが , より良い , 新しいバージョンのコンパイラをリリース するに従って , L 。 ki が提供している全ての機能を利用できるようになるでしよう。 Loki のコードと本書を通じて解説しているコード例では , Herb sutter によってまとめられたポピュラーな コーディング規則を採用しているため , すぐに慣れることができるでしよう。コーディング規則を簡単にまとめ ると :

6. Modern C++ Design

6.9 マルチスレッド対応 157 るのです。この時点でけりがついているのです。つまり , ポインタは初期化されているか null であるかのいず れかです。以下は , Double-Checked Lock ⅲ g パターンを理解し , それを味わうためのコードです。実際 , この コードにコンピュータ・エンジニアリングの美を感じることができるでしよう・ Sing1eton& Sing1eton: : 工 nstance ( ) if ( !p 工 nstance) Guard myGuard (lock-) ; if ( ! p 工 nstance-) p 工 nstance— -1- つっ ) 4 ・ new Sing1eton ; return *p 工 nstance— スレッドの制御フローがトワイライト・ゾーンに入ったと考えて下さい ( / / 2 の行 ) 。ここには , いくっかの スレッドが同時に到達する可能性があります。しかし , 同期化されたセクション内には , 同時に高々 1 つのス レッドしか入ることができません。つまり / / 3 で , トワイライトは消え去るのです。全てはクリアになってい るため , ポインタは完全に初期化されているか , まったく初期化されていないかのいずれかなのです。 ーこに到 達した最初のスレッドが変数の初期化を行い , 他の全スレッドは / / 4 のテストで失敗するため , 余計なものを 生成しないわけです。 最初のテストは迅速かっ粗いものです。 SingIeton オプジェクトが利用可能になっている場合 , それが取得 できます。そうでない場合 , より詳細な判定が必要となるわけです。 2 番目のテストは遅いけれども正確なもの です。つまり , これによって SingIet 。Ⅱが本当に初期化されているか , それともこのスレッドに初期化責任が あるのかが明確になるのです。これが Double-CheckedLocking パターンです。これで , 高速かっ安全なものを 手に入れることができたわけです。ほとんどの場合 S ⅲ glet 。Ⅱのアクセスは高速なものとなります。しかも構築 中は , 競合条件が発生しないのです。素晴らしい ... のですが . 経験豊富なマルチスレッド・プログラマであれば , Double-Checked Lock ⅲ g パターンが机上で正しく動作し ていても , 現実にはそれが常に正しい動作をするわけではないということを知っています。ある種の対称型マル チプロセッサ環境 ( 疎結合メモリ・モデルと呼ばれる機能を持ったもの ) では , メイン・メモリへの転送が 1 つ ずっ順番に行われるのではなく , バースト・モードで行われます。こういった転送は , アドレスの昇順に従って 行われ , 時系列に沿った形では行われません。こういった転送順序の違いによって , あるプロセッサにおける ある時点のメモリは , 他のプロセッサから見た場合 , 正しい順序で命令が実行されていないように見える場合 があるのです。具体的には , 該当 Sing1et 。 n オプジェクトが正しく初期化される直前に , あるプロセッサによ る plnst ce ーへの代入が発生する場合もあるのです。従って , こういったシステムに対しては , 残念なことに Double-Checked Locking パターンを使用することができないわけです。 結論として , Double-CheckedLocking パターンを実装する前には , コンパイラのドキュメントを熟読しなけ ればならないのです。 ( これによって TripIe-CheckedLocking パターンが必要となります。 ) 通常の場合は , プ ラットフォーム毎に , メモリのアクセス順序を保証するメモリ・バリアのような環境に特化した並行処理制御プ リミテイプが提供されています。少なくとも , plnstance- の次に volatile 修飾子を置くことです。適切なコ

7. Modern C++ Design

106 5.1 Com m a nd デザイン・パターン 第 5 章汎用のファンクタ GoF ( G 佖可 ) 本、 1 (Gamma 他 1995) によれば , C 。 mmand パターンの目的はオブジェクト中に要 求をカプセル化することであるとされています。 Command オプジェクトとは , そのコマンドを実際に実行する 場所から遠く離れた所で用意されるものです。 C 。 mma Ⅱ d パターンの一般的な構造は , 図 5.1 の通りです。 このパターンで重要な役割を担うのは , c 。 mm d クラス自身です。その最も重要な目的は , システムにおける 2 つのパーツ間 , つまり起動側と受信側の依存関係を低減することにあります。 典型的な動作の流れは以下のようになります : 1. アプリケーション ( 利用者側 ) は c 。 nc て etec 。皿 d オプジェクトを生成します。その際 , 作業を行えるだ けの十分な情報を引き渡します。点線は利用者側 (C1ient) が c 。 ncreteC 。 mm d の状態に影響を与える ということを示しています。 2. アプリケーションは , concretecommand オプジェクトの Command インタフェースを起動側 (invoker) に 引き渡します。起動側はこのインタフェースを保存します。 3. その後 , 起動側は該当動作の実行タイミングを決定し , 適切なタイミングで Command の Execute 仮 想メンバ関数を発行します。すると仮想関数の呼び出しメカニズムによって , 詳細な作業を実現する ConcreteCommand オプジェクトへの呼び出しがディスパッチされます。 ConcreteCommand は , Receiver オプジェクト ( 仕事を行うオプジェクト ) の Acti 。 n メンバ関数を呼び出すといった形で実際の処理を実行 するわけです。また , concretecommand オプジェクトは , 自分自身で全ての処理を実行することもできま す。この場合 , Receiver は図から無くなります。 起動側は , 自分自身の都合がよいタイミングで Execute を起動することができます。 こで重要なのは , 起 動側が保持している command オプジェクトを置き換えることによって , 実行時に様々な動作を差し替えられる ということです。 さらに 2 つの特筆すべき点も述べておきましよう。まず 1 つ目は , 作業がどのようにして行われるのかを 起動側は気にしなくても良い点です。これは新しいコンセプトというわけではありません。例えば , ソートの アルゴリズムを用いる場合 , その実装を知る必要はありません。しかし Command パターンの場合 , 起動側は Command オプジェクトがどういった類の作業を行うのかといったことすら気にしなくても良いのです。 ( 対照的 に , ソートのアルゴリズムでは , どういった効果が得られるのかが判っているはずです。 ) 起動側は , ある状況 が発生した場合に , 起動側が保持している command インタフェースの Execute を呼び出すだけなのです。また 受信側自身も , Action メンバ関数が起動側によって呼び出されたのか , その他のものによって呼び出されたの かを気にする必要がないのです。 このようにして c 。 mm d オプジェクトは , 起動側と受信側の分離という重要な性質を保証するわけです。っ まり , これらは互いにまったく不可視であるかもしれないものの , command オプジェクトを介することによって 通信し合うことができるわけです。通常の場合は , AppIication オプジェクトが起動側と受信側の関係を設定 します。これは , 特定の受信側オプジェクト群に対して様々な起動側オプジェクトを使用したり , 特定の起動側 、 1 訳注 : 「オプジェクト指向における再利用のためのデザインパターン」のことです。この本は , 著者が Erich Gamma, Richard Helm, Ralph Johnson, John VIissides の 4 名であることから「 4 人組」を意味する Gang of Four と呼ばれています。 John Vlissides は、本書 "Modern C 十十 Design' の推薦も書いているのに、お気づきでしよう。

8. Modern C++ Design

Scott Meyers による本書推薦の言葉 XI イディオムやデザイン・パターンの実装を生成するテンプレートの開発過程で , 全ての実装者が直面する設計 上の様々な意思決定に Andrei は取り組んでいます。コードはスレッド・セーフであるべきなのか ? スマート・ ポインタの参照外しに先だって , nu Ⅱ値のチェックを行うべきなのか ? プログラムの終了処理中で Singlet 。 n の破棄コードが , 既に破棄済みの他の Singleton を使用しようとした場合 , どうするべきなのか ? Andrei の目 標は , いずれかを指定するのではなく , 設計上で可能な選択を利用者に対して「全て」提供することなのです。 こういった意思決定をポリシー・クラスという形でカプセル化し , このポリシー・クラスを 彼の解決策とは , テンプレート・パラメータとして引き渡せるようにし , また適切なデフォルト値をクラスに対して設定しておく ことにより , 大半の利用者がそういったことを気にせず使用できるようにすることなのです。結果は驚くべきも のです。例えば , 本書で扱っているスマート・ポインタのテンプレートにはたった 4 つのパラメータしかありま せんが , これによってそれぞれが独自の動作を行う 300 種類 ( ! ) ものスマート・ポインタ型を生成できるので す。しかし , デフォルトのスマート・ポインタで満足できるプログラマは , ポリシー・パラメータを無視し , ス マート・ポインタが指すオプジェクトの型のみを指定するだけで , 実質的に何もしなくても , 巧妙に作り上げら れたスマート・ポインタ・クラスの利点を享受することができるのです。 最後に本書は , 3 つの技術的な話題を説得力ある方法で提供しています。まず第 1 は , 0 + におけるテンプ レートの強力さと柔軟性に対する新しい観点を提供している点です。 ( タイプリストの話題であなたがシャッポ を脱がなかったとしたら , それはあなたがシャッポそのものをかぶっていなかっただけなのでしよう。 ) 第 2 は , イディオムとパターンの実装の違いに横たわっている直交した次元を識別している点です。これはテンプレート 設計者やパターン実装者に対して重要な情報となるものですが , イディオムやパターンについて書かれたほとん こういった類の分析までは行われていないのです。第 3 は , Loki ( 本書で解説しているテンプ どの解説書では , レートのライプラリ名 ) のソースコードが公開され , 無料でダウンロードできるため , Andrei が考察しているイ ディオムとパターンに対応するテンプレートの実装を実際に試してみることができる点です。あなたが使ってい るコンパイラのテンプレート機能に対する負荷テストが行えるということはさておき , このソースコードをあな た自身が設計するテンプレートの素晴らしいスタート地点とすることができるはずです。もちろん , Andrei の コードを取り出して ( 合法的に ) 使用することもできます。彼自身も自らの努力を多くの人々に利用してもらい たいと考えていることでしよう。 私の見たところ , テンプレートを取り巻く状況は , 1995 年に私がそれについて記述することを避けた時から どんどん変わってきています。この速度で変革が続いていくとしたら , 私がテンプレートについて記述すること は , まずあり得ないでしよう。しかし幸いなことに , 私よりも勇ましい人達が沢山います。 Andrei はそういっ たパイオニアの 1 人なのです。彼の書籍から多くのことを学べるはずです。私も多くを学んだのですから。 Scott Meyers 2000 年 9 月

9. Modern C++ Design

105 第 5 章 汎用のファンクタ この章では , オプジェクト間の通信を切り離してパワフルな抽象化を行うことができる , 汎用のファンクタに ついて解説しています。汎用のファンクタは , 処理要求をオプジェクトとしてカプセル化するような設計を行う 場合 , 特に有効なものとなります。要求のカプセル化を行ったり , それに伴う汎用のファンクタを実現するもの として , Command デザイン・パターンというものがあります (Gamma 他 1995 ) 。 簡単に言えば , 汎用のファンクタとは C+ + で許されている任意の処理起動を , 型の安全性を持ったファース ト・クラス・オブジェクトとしてカプセル化したものです。より詳しい定義に従えば , 汎用のファンクタは : ・引数の一部または全てとして , 単純な関数へのポインタ , メンバ関数へのポインタ , ファンクタ , その他の 汎用のファンクタといったものを受け付けます。これによって , 任意の処理の起動がカプセル化できます。 ・誤った関数への誤った引数型とは適合しません。これによって , 型の安全性が保証されます。 , 代入 , 値による引き渡しが完全にサポートされているため , 値のセマンティックスを伴ったオブ コピー ジェクト ( 0 り e ん e semantics) となっています。汎用のファンクタは自由にコピーすることがで き , 仮想メンバ関数を公開していません。 汎用のファンクタによって , 処理要求を値として格納し , それをパラメータとして引き渡し , その生成場所か ら遠く離れたところで起動させることが可能になるのです。これは関数へのポインタをかなり現代風にアレンジ したものと言えます。関数へのポインタと汎用のファンクタにおける本質的な違いは , 後者が状態を保存でき , メンバ関数を起動できる点にあります。 本章を読むことで , 以下の収穫が得られるでしよう : ・ Command デザイン・パターンが理解でき , それと汎用のファンクタとの関連も理解できます。 ・ Command パターンと汎用のファンクタが有効となる局面を知ることができます。 ・ 0 + における様々な関数形態のメカニズム , およびそれらを統合したインタフェースとしてカプセル化する 方法を理解できます。 ・処理要求やパラメータの一部または全てをオプジェクト中にカプセル化する方法が理解でき , それを自由に 引き渡して起動できるようになります。 ・多重化された遅延呼び出しを連携させ , 順に実行させることができます。 こで解説している機能を実装した , パワフルな Functor クラス・テンプレートの使用方法を理解でき ます。

10. Modern C++ Design

249 第 10 章 Visitor この章では , Visitor デザイン・パターン ( Gamma 他 1995 ) を用いたジェネリック・コンポーネントについ て考察しています。 Visitor は , クラス設計に関連する依存性のトレード・オフを変更できる強力なーある意味 賛否両論のあるデザイン・パターンです。 Visitor によって , ある種の分野では驚くほどの柔軟性を手に入れることができます。クラス階層や既存コー ドを再コンパイルすることなく , 仮想関数を追加することができるようになるのです。しかしこういった柔軟 性は , 設計時にある種の機能を放棄するという代償を払わなければ得られないのです。その代償とは , 階層の 末端にクラスを追加した場合 , 階層や全ての既存コードの再コンパイルが必要になるというものです。従って Visitor の活躍場所は , 非常に安定した階層中 ( 滅多に新たなクラスが追加されない ) , かっ厳しい処理が要求さ れる ( 頻繁に新たな仮想関数の追加が発生する ) , 必要性のある場合に限られるわけです。 また , Visitor は , プログラマの直感に反したものとなっています。従って , 注意深い実装と厳密な規律が必 要不可欠となります。この章の目標は , アプリケーション・プログラマに対してなるべく負担を掛けないよう な , 信頼できるジェネリックな Visit 。 r の実装を作り上げることです。 本章を読み終えることによって , 以下のことが得られるでしよう : とができます。 ・あなたの問題に特化したⅥ sitor を実装するための , 強力なジェネリック・コンポーネントを手に入れるこ ・ Visit 。 r の実装をライプラリへと移動する際に持ち上がってくる , ほとんどの意思決定方法が判ります。 ・ G 。 F の Visit 。 r 実装における欠点のいくつかを克服する方法が判ります。 ・ Visitor の基本的な実装 (GoF の実装 ) が理解できます。 ・ Visitor パターンをいつ適用し , いつ適用しないかにの判断も重要です ) が判るようになります。 ・ Visitor の動作方法が理解できます。 一方 , 新たな仮想関数の追加は難しい作業です。ポリモフィズムに則った形で ( ルート・クラスへのポインタ を変更したり , 再コンパイルする必要はありません。こういったコードの再利用ができれば最高なのです。 新たなクラスの追加は簡単です。クラスを導出して , 必要な仮想関数を実装すれば良いのです。既存のクラス たな仮想メンバ関数を追加するかのいずれかによって実現できます。 まず , クラス階層に機能を拡張する場合を考察してみましよう。機能拡張は , 新たなクラスを追加するか , 新 10.1 Visitor の基本