BoostのVisual Studio Debugger Visualizers

Visual Studioには2005からDebugger Visualizersという機能がこっそり入っていて
そのおかげでSTLコンテナの状態がデバッグウィンドウで見やすくなっています。


デフォルトでDebugger Visualizersが有効になっているので、
vectorデバッグしてみると以下のようにデバッグウィンドウに表示されます。


Debugger Visualizersを無効にした場合は以下のように表示されます。

これを見れば、Debugger Visualizersのおかげでどれだけ見やすくなっているかがわかると思います。
なんだかよくわからない値ではなく、要素数と要素がはっきりわかるようになっています。


Debugger Visualizersは、コンパイラに同梱されたライブラリのみに適用されるだけでなく
ユーザー定義のライブラリにも適用することができます。


Visual Studio 2005の場合、
「Microsoft Visual Studio 8\Common7\Packages\Debugger\autoexp.dat」に
Debugger Visualizersのソースが置いてあります。


vectorのところを見てみると、以下のような記述になっています。

[Visualizer]
; This section contains visualizers for STL and ATL containers
; DO NOT MODIFY
...

std::vector<*>{
   children
    (
        #array
        (
            expr :  ($c._Myfirst)[$i],  
            size :  $c._Mylast-$c._Myfirst
        )
    )
    
    preview
    ( 
        #( 
            "[", 
            $e._Mylast - $e._Myfirst , 
            "](", 
            
            #array
            (
                expr :  ($c._Myfirst)[$i],  
                size :  $c._Mylast-$c._Myfirst
            ), 
            ")"
        )
    )
    

}

構文はアンドキュメントではありますが、とてもシンプルなのですぐ覚えられると思います。
private変数を直接参照し、プレビューと展開時の表示形式を設定する、というくらいです。


さて、前振りはこれくらいにして。
最近、BoostでもこのDebugger Visualizersに対応するためのプロジェクトが始まっています。

https://svn.boost.org/trac/boost/wiki/DebuggerVisualizers


すでに対応している型は、以下になります。

  • boost::array
  • Boost.PtrContainer
  • boost::optional
  • boost::multi_index_container
  • boost::shared_ptr
  • boost::posix_time::ptime, boost::posix_time::time_duration
  • boost::regex
  • boost::variant

なんとmulti_index_containerまであります!
boost::variantは泣いて喜ぶひともいそうですね。
ざっと見ると、ほしいものはだいたい揃ってます。
まだないのはBoost.Unordered、Boost.Graph、Boost.Intrusiveあたりでしょうか。


これらの型をVisual StudioのDebugger Visualizersに適用するには、まず
https://svn.boost.org/svn/boost/sandbox/boost_docs/subprojects/DebuggerVisualizers
からほしい型のテキストファイルを開きます。
ここでは「boost__optional.msvc8.vis.txt」を選択します。


そのテキストを、先ほどのDebugger Visualizersのソース「autoexp.dat」の

[Visualizer]
; This section contains visualizers for STL and ATL containers
; DO NOT MODIFY

と書かれているところの下に貼り付けます。
はい、これでおしまいです。

では、boost::optionalのデバッグをしてみましょう。


Debugger Visualizersの適用前:

Debugger Visualizers適用後:

boost::optionalに値が入ってなかったら「?」が表示され、
値が入っていたらその値が表示されています。
すばらしく見やすくなりました。


この手順は、ほかの型でも同じですが、multi_index_containerだけは少々めんどくさいです。
まず、multi_index_containerのDebugger Visualizersのソース
「boost__MI.msvc8.vis.txt」を開き、
autoexp.datにそれを貼り付けます。ここまでは同じです。


次に、BoostのDebugger Visualizersのページにある「mic_visualizer.hpp」をダウンロードしてきます。
それと、Boost.MultiIndexを使用したソースにもmic_visualizer.hppを使用するよう書き換える必要があります。

#define BOOST_MULTI_INDEX_LIMIT_INDEXED_BY_SIZE    5
#define BOOST_MULTI_INDEX_LIMIT_TAG_SIZE           3
#define BOOST_MULTI_INDEX_LIMIT_COMPOSITE_KEY_SIZE 5
#include "mic_visualizer.hpp"

#include <iostream>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>

using namespace boost::multi_index;
typedef
    multi_index_container<int,
                          indexed_by<
                            hashed_unique<identity<int> >,
                            sequenced<> > > container;

VISUALIZE_MULTI_INDEX_CONTAINER(container);

int main()
{
    container c;
    c.insert(3);
    c.insert(1);
    c.insert(4);

    return 0;
}

これでおしまいです。デバッグしてみましょう。

multi_index_container内の要素数と要素、インデックスがはっきりわかるようになりました。


multi_index_containerだけ手順が多い理由ですが、
Debugger Visualizersの構文は、配列、リスト、ツリーに特化した構文が用意されていますが、
実装詳細にかなり依存します。
multi_index_containerはDebugger Visualizersのいずれの構文にも適用することができないため、
配列の構文で表示できるように、operator[]でランダムアクセスできるようにするための型をわざわざ用意しています。
私もboost::unordered_mapをDebugger Visualizersに適用しようと思っていますがこのへんでつまずいています…。
完成したらブログで公開し、Vaultにも提出しようと思います。


それと、BoostのDebugger Visualizersは現在、Visual Studioのみに対応していますが、
gdbにも同じような機能があるらしく、

gdb-stl-views

今後そちらに対応する予定もあるとかないとか。


とにかく、まずは試してみるといいと思います!