読者です 読者をやめる 読者になる 読者になる

北海道苫小牧市出身の初老PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

Boost.勉強会なう

今日はBoost C++ Librariesを遊び倒す会(ATND)に参加しています。ustreamもあるそうです。

C++は新卒の頃に数ヶ月触ったキリで、先月勉強再開し始めたばかりなので、正直心配です(ぉ。Hello Worldだけは今朝実行しました!

Boostライブラリ一周の旅 - faith_and_braveさん

  • 1.40.0のライブラリの概要
  • テンプレートメタプログラミング
    • テンプレートのインスタンスかを利用
    • メタ関数: テンプレートパラメータ + typedef
    • 分岐は特殊化、呼び出しは適用
    • メタ関数の例を紹介
  • Accumulators: 統計計算
  • Any: あらゆる型の保持
  • Array: 組み込み配列にコンテナインタフェースを付加

ここでマシントラブルで再起動中断w

  • Asio: 非同期ネットワーク
  • Assign: コンテナの構築を簡単にかける(v += 3, 1, 4とか)
  • Bimap: キー←→バリュー の相互呼び出しが機能なmap( left と right )
  • Bind: 部分評価( 例えば、thisをbindすると便利 )
  • Circular Buffer: 循環バッファ
  • Compressed Pair: 最適化がされやすいpair
  • Concept Check: テンプレートパラメータに制約を加える
  • Conversion: 型変換
    • lexical_cast: 数値と文字列
    • polymorphic_downcast: デバグ時のみdynamic_cast的なstatic_cast
    • polymorphic_cast: 例外を投げる dynamic_cast
  • CRC: チェックサムとか
  • Date Time: 日付計算
  • Dynamic Bitset: Static bitsetの動的版
  • Enable If: 型特性でオーバロード(整数型(is_integral)と整数型以外でわける、など)
  • Exception: catchの度にエラー情報を足せる例外
  • Filesystem: OS非依存のパス、ファイル、ディレクトリ操作
  • Flyweight: デザパタ(同じオブジェクトであればリソースを共有する)
  • Foreach: BOOST_FOREACH
  • Format: sprintf を std::string に対応させたもの
  • Function: 関数ポインタと関数オブジェクトを同じ形式で使えるようにする
  • Function Types: 関数のメタ情報
  • Fusion: タプルのライブラリ (Fusionはコンパイル時と実行時の融合の意)
    • コンパイル時にタプルの定義を操作(pop_backなど)、実行時にタプルの操作(for_eachなど)
  • GIL: 画像処理
  • Graph: グラフ構造
  • Interprocess: 共有メモリ
  • Interval: 区間計算 (in 区間 とか 区間の合成とか)
  • Intrusive: オブジェクトの参照を持つコンテナ(侵入コンテナ)
  • IO State Server: IO Streamの状態管理
    • 例えば、スコープを抜けたら、Streamの状態が戻るようにする
  • Iostreams: IO Streamの拡張
    • 例えば、StreamへのUNIXライクなfilterの実装
  • Iterators: イテレータの定義を簡単にする
  • Lambda: 動的に関数オブジェクトを作る( _1 のようなプレースフォルダによる )
  • Math: 数学系
  • Member Function: mem_funとmem_fun_ref を一般化
  • MPL: テンプレートメタプログラミング用のライブラリ
  • MultiArray: 多次元配列。サイズがとれたりする。
  • Multi Index: ソート順やアクセサ順を複数持つコンテナ
  • Numeric Conversion: 数値型を変換 (DoubleToInt等)
  • Operators: 演算子の自動生成( > を定義すれば <= や >= が自動生成 )
  • Optional: 無効値( boost::none )の定義
  • Parameter: 名前つき引数(f( _name="hoge" ) を args[_name] で受ける感じ)
  • Pointer Container: ヒープオブジェクトを格納するコンテナ。メモリの節約。
  • Pool: メモリのプール
  • Preprocessor: プリプロセッサによるメタプログラミングのライブラリ
    • 例えば、コード自動生成とか
  • Property Map: iterator_traitsの拡張版
  • Proto: Expression Template 用のライブラリ。評価を後でできる。
  • Python: C++Pythonの相互利用のライブラリ (BOOS_PYTHON_MODULE とか def() とか)
  • Random: 乱数生成エンジンと分布を分けて指定可能
  • Range: ベクターや配列を同じ感じ(begin, end)で使う
  • Ref: テンプレートパラメータを明示的に参照とする
  • Scope Exit: 関数を抜ける時に実行されるブロック
  • Serialization: シリアライズとデシリアライズ(serializeメソッドを定義)
  • Signals2: シグナルとスロット(イベント系)
  • Smart Pointers: new したら勝手にdeleteされるポインタ
  • Spirit: 構文解析( qi::parseとか >> とか )
  • Statechart: 状態マシン
    • meta state machine ってのもあるらしい
  • Static Assert: コンパイル時のアサート。BOOST_STATIC_ASSERT
  • String Algo: 文字列のアルゴリズム。to_upperとかtrim_rightとか
  • Swap: std::swapの強化版。特化したswapがすでにあればそのロジックを使うもの。
  • System: OS非依存のエラーコード
  • Test: 単体テストライブラリ
  • Thread: スレッド。joinとかの実装。移植性。
  • Timer: 時間計測。定義 → t.elapsed() までの時間
  • Tokenizer: トークン分割
  • Tribool: 3値のbool。true, false, indeterminate
  • Tuple: std::pairの3つ以上版。戻り値として使う等。
    • 取り出しは tie(n, ignore, d) (ignoreは捨て)
  • Typeof: 型推論。BOOST_TYPEOF(c++0xのdecltype)とBOOST_AUTO(C++0xのauto)
  • uBLAS: 線形代数。高速らしい
  • Units: 単位変換。mとか。
  • Unordered: ハッシュテーブルによる連想コンテナ。std::mapとほぼ同じ
  • Utility
    • boost::noncopyable: コピー禁止クラスを作る
    • boost::result_of : 戻り値の型を取得
  • Variant: 指定した型の格納ができるUnion
  • Wave: C++,C99プリプロセッサの拡張ができる
  • Xpressive: 正規表現ライブラリ

この時点でスケジュールの40分押しですねえ・・・。


Boost.MultiIntrusivedex - k.inabaさん

MultiIndex
  • データ構造好き
  • MultiIndex 複数のインデックス
  • 例: 2つのIDによる検索、ソート
    • for_eachではだめ
    • std::setを使って、検索を速く
    • 複数パターンでの検索 → Boost.MultiIndex
  • boost.MultiIndex
    • multi_index_containerでコンテナを定義
    • indexed_by, orderd_unique, sequenced でインデックス指定
    • get<インデックス番号> のような使い方
  • Q.: 三つデータ構造を作るのとどう違う?
    • A. 容量の都合と、更新時の整合性。
  • インデックスの種類
    • ordered_(non_)unique, hashed_(non_)unique, sequenced, random_access
  • 普通のsetよりも便利なことも多い(検索にインスタンスが要らないとか)
Intrusive
  • データ内に、リスト管理用のフィールドを侵入させる
    • 通常は構造の管理データは外にある
  • メリットとかデメリットは別として・・・setの種類が多い!!
    • set, avl_set, sg_set, splay_set, treap_set: マニアックなset達
混ぜる
  • avl, aplay, sg, treap のIndexをMultiIndexに実装
    • いまはまだ出来ないらしい。ソースを読んで予想した。
  • ノードクラスを作る( 全てのインデックスに関するデータを格納してある )
    • 利点: 1つのノードから、任意のインデックスによって隣接するノードを全て見つけられる
    • 継承で実装されている。インデックスを追加するごとに継承でフィールドを作る
  • 親クラスを後から指定できるようにして、俺ノードを作る
    • 継承チェーンは毎回変わるので
  • インデックスの実装も継承。外からMetaクラスを差し込む
  • メソッド例: pop_back
    • final_erase_を使い、全インデクスに削除をしてもらう必要がある
    • erase_ は自分のインデックスの削除を実装
  • IndexSpecifierを作る: 指定するインデックスの名前 (node_classとindex_classを持つ)
  • githubにあげてあるよ!!
  • 質疑応答
    • Q. 計算量を書くだけでインデックス貼られるようにならない?
    • A. 面白そう。
    • Q. インデックスの順番は定数値ってどうなの?
    • A. 名前(タグ)もつけられる。class Tag で指定可能

LT

俺Tokenizerを作る - tt_clownさん
  • scanf風のクラス
  • Boost.Tokenizer のカスタマイズ
    • ポリシー・クラスの自作によるカスタマイズ例
    • Modern C++ Designの設計思想。動作をDI可能にする。
    • class TokenizerFuncがポリシークラス
    • ()演算子とかresetを利用 (実装はブログ見てね)
  • FormatSeparatorの実装
    • %sだけ実装
    • 型変換は scanner
  • まとめ: ポリシークラスで抽象化するとカスタマイズ性が上がるよ
Boost.Graph 入門の入門 - egtraさん
  • vertexとedgeからなるデータ構造の表現
  • 有向グラフも無向グラフもOK
  • adjacency_list<> : グラフ
  • add_vertex, add_edge
  • verticesをBOOST_FOREACHで頂点を辿る
  • adjacent_vertices(隣の頂点)、adjacent_edges(接する辺)
  • 探索などの関数もある
  • source, target, edge, edge_range, vertex
  • adjacency_list のテンプレート引数の多さで難しく見える
    • OutEdgeList, VertexList, Directed, 以外の引数は入門的には使わない
    • プロパティマップ(頂点とプロパティを紐付け)
    • アルゴリズム(深さ優先、巾優先、トポロジカルソート)
    • Graphvizフォーマット
Introduction to The Boost.Polygon library - dark-yoshiさん
  • 平面多角形幾何データの操作のアルゴリズムらしい
    • まだBoostライブラリには入ってない
  • 機能
  • Point、Polygon、Rectangleの利用例
    • set_points とか equivalence とか contains とか area(面積)とか。
  • std::vectorとstd::listの利用例
    1. や*を形状の論理演算に使える
  • OpenGLでPolygonを表示する - for_eachで回してGLの命令で1つずつ描画
  • get_trapezoids : OpenGLが描画できるように、四角形に分割
  • デモ

Boost.Coroutine - melponさん

  • 関数の実行を凍結、再実行させる機構
  • self& self, self.yield, self.exit
  • 別名: micro-thread, fiber, continuation
  • スレッドと類似: 手動のコンテキストスイッチなので同期がとりやすい
  • 正式に入っているライブラリではない
    • Boost.Vault から持ってくる
    • 12/1版でスタックが壊れるバグが直ったみたい
  • 使い方
    • coroutine : Tはyield時の戻り値
    • coroutine::self& を引数にとる関数で初期化
    • generator とすると、イテレータと同じ使い方が出来るようになる。
  • Coroutine の使用例: シューティングの弾の動きを1関数内で直感的にかける
  • generator の使用例
    • EnumWindows(コールバックをとる) をイテレータ風に使えるように書き換える
  • 実装について
  • コンテキストの実装
    • スタック、レジスタ、(例外情報)
    • 切り替え: 情報を保存->スタックポインタの書き換え→情報をロード→PCの書き換え
    • アセンブラのコード例
  • 他の方法での実装
  • Coroutineの未来
    • 作者は元気だけどやる気がない
    • 作者以外の人が頑張っている
    • Boost.Fiber も出て来ている
    • 自分で作ったほうがいいかも
  • まとめ: Boost.Coroutine は 実装の模範例とみよう
  • 質疑応答
    • Q. self.exitって?
    • A. 例外を投げてる
    • Q. 終了するのでは?
    • A. 実装は例外を投げて受けている。終了するという認識でよい。
    • Q. 終了後呼ぶと例外を出すのでは?
    • A. 終了後呼ぶと例外が出る。std::nothrowを使うと例外が飛ばない。

Boost.Asio - xyuyuxさん

  • Asio は Asynchronous I/O の省略
    • スレッドやロックを使わずにブロックを処理する
    • 元々はネットワーキングリソースを想定
  • UDP
    • boost::asio::io_service, udp::socket, udp::resolver, receive_from
  • TCP
    • tcp::iostream (普通にreadlineとかできる)
  • タイマー処理
    • deadline_timer, t.wait()
    • t.async_wait(), io.run() - 代わりにlambdaを読む
  • 休憩
    • Asioの作者が、マクロでCoroutineを作ったらしい
    • reenterがswitchでyieldがcaseでforループをcaseで飛び越えてうんぬんかんぬん
  • 閑話休題
  • ssl::context 簡単(?)に暗号化。要OpenSSL
  • serial_port 簡単(?)にシリアルポート
  • プラットフォームごとの実装の違い
    • select ,epoll, poll, kqueue, overlapped I/O, I/O completion ports などなど
  • 非同期シングルスレッド時
    • io_suervice の run() を呼ぶと、 io_service がコールバックや OS とやりとり
    • マルチスレッドにすると、run()が複数のWorkerスレッドから呼ばれる

Boost.Preprocessorでプログラミングしましょう - DigitalGhostさん

  • Preprocessor で FizzBuzz の例 : gcc -P で展開すると動く
  • 実行環境: cl.exe、cpp -P
  • hello.cpp
    • 簡単!
Hello, World!
  • BOOST_PP_ENUM_SHIFTED : 数字を増やしつつコピペするマクロ
  • BOOST_PP_ENUM_SHIFTED_PARAMS : 数字付きのパラメータを作る
  • BOOST_PP_SHIFTED_BINARY_PARAMS : ダブルで展開
  • BOOST_PP_CAT : 結合
    • ## と展開順序が違う
    • 実装は、間にBOOST_PP_I を挟んでいるだけ
  • BOOST_PP_IIF 1か0の判定。それ以外は駄目。
    • 1LLや1.0 は駄目
  • プリプロセッサでは、括弧やカンマ以外はトークンになる
  • BOOST_PP_BOOL : 整数を1か0に変換、 BOOST_PP_NOT : 論理否定
  • BOOST_PP_IS_EMPTY : 空トークンのみ 1
  • BOOST_PP_MOD, BOOST_PP_ADD, ... : 四則演算
    • 1 + 1 とかは認識できない。ADDを使うこと
  • 実装
    • BOOST_PP_ENUM_SHIFTED で FIZZBUZZ_OP に展開
    • C++実装を書いて、BOOST_PPな命令で置き換えていく
  • 例: タプルを作る。
    • const の有無で、2の階乗個定義が必要
    • ブログ参照
  • 代入: defineだとundefすると展開が起きなくなる → BOOST_PP_ASSIGN_SLOT
    • Boost.Typeof で利用しているらしい
  • BOOST_PP_ITERATE : BOOST_PP_ENUM では大き過ぎる場合
  • 注意: BOOST_PP_AUTO_REC マクロが読みにくいので注意。
    • ブログを見て!
  • 質疑応答
    • Q. なんで始めたの?
    • A. そこにプリプロセッサがあったから。
    • A. C++0xでは可変長引数のマクロが使える。
    • Q. 実行時の可変長をやるためにBoost使うことが多いが、C++0xでどう改善される?
    • A. 大半消えると思う
    • Q. 型チェック時の副作用は必要。ファイルとか読めるといいと思いますよね?
    • A. そこまでは・・・。まあたまには。
    • Q. デバグはどうするの?
    • A. gcc -P でできます。ライブラリの中にマクロがあるっぽいけど調べてない。
    • Q. Boost.Preprocessの展開を途中で止めることは?
    • A. なかなか難しい。Boost.Wave に手を入れてステップ実装とか。

バグベアード入門 - wraith13さん

  • Boost C++ Libraries とは別。英語コミュニケーションできる人手伝って欲しい
  • printf デバッギング用のヘッダーファイル bug.h
  • 機能
  • 特徴
  • 使い方
    • bug.hをダウンロード
    • おまじないを書く(10行弱。デバグ版とプロダクト版を分ける。出力ファイル指定など)
    • BUG_puts, BUG_FORM, BUG_VAL(整形してくれる),
    • BUG_STATEMENT_HACKをdefineすると、ステートメントのログが自動で表示される
    • Windowsに特化したユーティリティ等
  • BUG_STATEMENT_HACK の制約
    • while 内とかで int iとかしちゃだめ
    • 例外仕様構文はだめ
    • undef BUG_STATEMENT_HACK して bug.h を include しなおせば、切り替えが可能
  • BUG_MULTI_THREADでマルチスレッド対応
    • ログはスレッド毎に別ファイルの指定が必要
  • プロファイリングは、プロファイル用のおまじないを指定
    • 合計自実働時間が遅いものがネックとなる部分
    • MinStampとMaxStampを比べれば最速動作と最遅動作の速さが見れる
  • カバレッジ
    • カウントが0の部分を追えばいい
    • 問題: switchは非対応、実行されないifは出ない
  • 悪魔の契約について
    • かなり外道なことをやっている → 読んで、了承の上defineしてね
    • 規格違反(ステートメントの置換)
    • エラー情報をバグベアードに食われる
    • 構文制限、動作の安定(コンパイラの違い等)
    • 詳細は、bug.h内のコメントを読むこと
  • ヒント
    • - ? - : - より if
    • returnを省略しない
    • フィルタ機能を使うとよい
  • 質疑応答
    • Q. コンパイル時間がかかるのでは
    • A. テンプレートメタプログラムよりは速い
    • Q. 実行速度は?
    • A. 当然遅い。リリース版には埋め込まないように。

Boost.SmartPtr:shared_ptr + weak_ptr - Cryoliteさん

  • 所有(ownership)
    • 権利: 誰かが捨てない → Dangling pointer防止
    • 義務: 自分が捨てる → Memory Leak防止
  • 共有: boost::shared_ptr
    • 誰が片付けるのか。使ってる人がいる。
    • 所有カウントによって、簡単に扱う
    • 0より大きければ、使ってる人が居る
    • 0になれば、誰も使ってない → 片付ける義務
    • 普通のポインタとして動作する (強いポインタ)*2
    • デリータ(後片付け)の実行も可能
    • カウンタについてスレッドセーフ
    • 循環参照を扱えない(開放されない)
  • shared_ptr 使い方
  • shared_ptrの設計思想
    • ポインタと同等の型互換、バイナリ互換
    • 非侵入性: 組み込み型に使えるか、再コンパイル、など
    • 効率、は上記二つの次。
    • shared_ptr が何を持つかは型に含まれない( コンストラクタで所有が決まる )
  • バイナリの境界を越える
    • 所有を開始する時に、deleteの処理が紐づいているのがポイント
  • shared_ptr により、削除を遅らせることができる
    • 削除が重い処理等。voidのshared_ptrで所有を続け、好きなタイミングで開放
  • weak_ptr: 弱いカウント
    • 所有カウントが0になると、所有物を片付ける
    • 弱いカウントが0になると、カウンタを片付ける
    • これにより、所有カウントの数(有無)に常にアクセスできる = 対象の生死を判定するプロクシ
    • weak_ptrからshared_ptr も作れる ( lock() )
  • 例: 普通のポインタからshared_ptr を作る
    • shared_ptr で自分の参照を持つと循環する。weak_ptrを使う
  • 例: Observerでよく起こる事故 = Subscriberがnotifyの時にはもう死んでいる
    • 死んだオブジェクトにアクセスしない、イベント通知中に死なせない
    • PublisherにSubscriberのweak_ptrを持たせる
    • Publisherがイベントを送る際に、lock()してshared_ptrを作る
    • →これはBoost::Signal2で実装されている
  • 例: オブジェクト間のグローバルマッピング
    • share_ptrにすると、map用のエントリがリークする
    • 案1) weak_ptr を使う。
    • 案2) カスタマイズしたデリータで、オブジェクトが消えたらエントリも削除する
  • 例: xとyに循環参照的にgetSharedを持たせる
    • 親のshared_ptrにxとyへのポインタを持たせる(循環させない)
  • まとめ
    • 所有は大事
    • shared_ptr: 所有カウントを使う。互換性が高い
    • weak_ptr: チェック、格上げ。
  • 質疑応答
    • Q. 最後の循環参照の問題は、weak_ptrとlock()でなんとかできないのか?
    • A. 今の文脈だと、うまく行く。ただ、xかyが死んでいる可能性がある。

Boost.MPL - uskzさん

  • コンパイル時無限リスト
    • Haskellだと、 iterate f e = [e, f e, f (f e), ... ]
    • repeat>(無限リスト) とか from>(0 からインクリメンタル)
    • take_viewの実装は・・・? → 遅延してアクセスするために sequence view を被せる
  • メタ関数の適用を、普通の関数風に書けないか( <> じゃなくて () )
    • C++03では、eval<> を定義して、テンプレート特化で場合分けかな?
    • C++0xでは、もっとスマートに書ける
  • 単位行列の作成
  • 識別子の生成 : C++0x可変長引数ではうまくいかない例
    • v[xxy] とか v[rgb]みたいなアクセス
  • Placeholder Expression
    • メタ関数じゃないのになぜ動くのか
    • _1とか_2って何? → typedef arg<1> _1; です
  • 質疑応答
    • Q. チャーチ数と関係あるの?
    • A. あると言えばある?


えと・・・お疲れ様でした!

余談: アンケートにご協力を!

[飛入]Boost.PHPについて - moriyoshiさん

  • きっかけ
    • Boost.Pythonが便利!
    • 本体へコミットもしている
    • PHPの拡張モジュールを簡単に作りたい
  • PHPの拡張は基本はCで書く
  • (PerlのXSと同様に)謎のマクロがたくさん必要
  • Boost.Pythonの関数を作るデモ(速い!!)
  • Boost.PHPのデモ
    • Boost.Pythonよりは多少煩雑
    • Boost.Preprocessor を使っているため、コンパイルは多少遅い

*1:BREWのCoroutineをJavaに移植したそうです。

*2:C++ では強参照が保証されていない