Q&A on our TR1 implementation

Visual C++ Team BlogからQ&A on our TR1 implementationを訳してみました。


Q&A on our TR1 implementation


こんにちは、VC++ライブラリ開発チームのStephanです。Visual Studio 2008 Feature Pack BetaはTR1の実装を含んでいますが、このテクノロジーに関するよくあるご質問にお答えしたいと思います。


Q. Feature PackはどのバージョンのVC++で動きますか?

A. Feature PackはVC++2008(VC9) RTMへのパッチです。以下には当てられません:

  • VC9 Express
  • RTM以前のVC9 (VC9 Beta 2とか)
  • 古いバージョンのVC (VC8とか)


Q: パッチを当てずにヘッダファイルをVC\includeにコピーするだけじゃだめですか?

A. だめです。VC9 TR1は新しいヘッダ(など)のほかに、既存のヘッダの修正版(など)や、新たにコンパイルされたCRTの追加コンポーネントなども含んでいます。ほとんどヘッダーファイルのみで構成されているとはいえ、完全にそれだけでもないので、パッチを当てた上で、アプリケーションには新しいCRTをつけて配布するようにして下さい。VC9 TR1は"サービスパック0"だと考えて頂けばよいと思います。


Q: TR1はMFCに依存しますか?あるいはMFCを更新するとTR1への依存するようになりますか?

A: いいえ。TR1とMFCの更新は無関係です。便宜上、一緒に配布しているだけです。


Q: この実装はTR1をどの程度カバーしていますか?

A: 我々の実装はTR1のほとんどを含みますが、仕様のセクション5.2および8 (http://open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf)は含んでいません。つまり、Boost由来のコンポーネントとUnorderdコンテナ(訳注:Hash)をご提供しています。


Q: このTR1が既存のヘッダを変更しているということは、その機能を使わなくても私のプログラムに悪影響を及ぼすことがあり得るのでしょうか?

A: そういうことは無いはずです(もしそういうことが起こったら、それはバグです。ぜひご一報ください)。実行時の振る舞いがおかしくなる事も、新しい警告やエラーを見ることも(少なくとも/W4の場合)ありません。もちろん、TR1はビルドをそれなりに遅くします(コードが増えますからこれは仕方ありません)し、プリコンパイルヘッダに関しては/Zmの限界にとても近い場合には追加のコードのために限界を超えてしまうこともあり得ます。そうした場合、プロジェクト全体に_HAS_TR1を定義することで、この新しいコードを無視することができます。


Q: このパッチはコンパイラIDEに影響しますか?

A: いいえ。


Q: DinkumwareのTR1実装をライセンスしているのですか?

A: そうです(http://dinkumware.com/tr1.aspxをご覧下さい)。標準ライブラリ実装と同様です。ですので、いつもどおりの高品質を期待してください。


Q: ではMSは何をしてるんですか?

A: 大雑把に言うと、"MS独自の"追加テストを行っています。


1. TR1をVC9に統合し、TR1をSTLのすぐ隣に配置しました。(ビルドシステムに関することとしては、独立にコンパイルされたTR1のコンポーネントをmsvc90.dllやその仲間に加えましたし、セットアップテクノロジに関しては、Visual Studioインストーラに新しいヘッダやソースを加えました。)その結果、ユーザはインクルードパスを変更したり、新しいDLLをアプリケーションに配布したりしなくても良くなりました。単にパッチを当ててCRTを更新するだけでよいのです。


2. TR1が/clrや/clr:pureで上手く機能するようにしました(これは標準C++の範疇外ですが、もちろん私たちはサポートしなければなりません)。当初、これらのスイッチはあらゆる種類のコンパイルエラーと警告を吐き出していました。例えば、内部で可変引数関数を呼ぶと言った簡単なものでさえ"native code generation"警告になる、といった具合です。これらを解決するのは時間が掛かりました。


3. サポートするあらゆるシナリオでTR1を/W4でコンパイルしても警告が出なくなるようにています。これは/Za, /Gzのようなスイッチも含みます。


4. TR1が/analyzeクリーンになるようにしています。
例によって、警告を無効にするためのワークアラウンドよりも、きちんと解決する方を選ぶようにしています(警告を無効にする場合はユーザコードに影響しないようにヘッダの中で完結するようにします)。


5. TR1のバグを特定し、Dikumwareとともに修正しています。Dinkumwareのコードははじめはとても堅実でした……しかしやはり目が増えればバグも見つかるものです。また、TR1仕様そのものにバグを見つけることもありました(http://open-std.org/JTC1/sc22/WG21/docs/lwg-active.html#726や後述のIssue 727を参照)。


6. 性能面でBoostと互角になるよう頑張っています(Boostは便利な参考実装です;GCCのTR1実装と比較することもできましたが、そうするとコンパイラの差を相手にしなければなりません)。いくつかの面でVC9 TR1ではその基準に到達できそうもありません(VC10では実現したいと思います)が、しかし既にかなり前進しています。MSの性能テストのおかげで見つけたregexマッチの性能問題では、Dinkumwareは(訳注:従来比で)4〜5倍の高速化を達成しました。(ただしこの修正はbetaには入っていませんので、マッチ動作は大雑把に(訳注:boostの)18倍くらい遅くなっています。現在のビルドでは3.8倍程度遅くなっています。)またfunctionでは互角の性能を達成しました(これもbetaには入っていません)。


(「でもregex::optimizeすれば速くなるんでしょ?」残念ながら、そうはなりません。regex::optimizeによるNFAからDFAへの変換はVC9 TR1では実装されていません。VC10には含めようと考えています。ざっと試してみたところ、Boost 1.34.1でもregex::optimizeは何もしていないようです。)


7. C++0xの機能からTR1にバックポートするものを決めています。例えば、shared_ptrやfunctionのallocatorのサポートなどです。TR1には入っていませんが、多くのカスタマ(我々のコンパイラもそうですが)にとってこれは重要な機能です。これはチェックインされただけで、ベータには入っていません。


8. TR1の型に対するIDEデバッガのビジュアライザを実装しています。STLと同様(あるいはそれ以上に)、TR1の型の表現は複雑で、ビジュアライザはデバッグを本当に楽にしてくれます。私はTR1の型のほぼすべてに対するビジュアライザを書きました(shared_ptrのビジュアライザが"1 strong ref"と"2 strong refs"で切り替わるあたりには、こっそり自信があります)が、ベータにはTR1ビジュアライザは一つも含まれていません。


9. DinkumwareとともにVC8 SP1とVC9 RTMで見つかっているわずかなバグを修正しました。TR1と実際に関係するものとしては、stdext::hash_set等のswap()が挙げられます。これは、O(N)で、例外を投げ、イテレータを無効にしていました (unordered_set等と実装の大半が共通だったために見つけることができました)。これは修正され、O(1)で、例外を投げず、イテレータを無効にしないようになっています。


10. TR1はSTLの傍らにあるので、性能を向上するためにお互いに話し合うようにしました。例えば、TR1の型に対するSTLコンテナ(例えばvector >やvector >など)は、要素のコピーを回避するようにしています。これはVC8やVC9のSTLコンテナのコンテナが要素のコピーを回避しているのと同様です。


これはVC8 STLのあまり知られていない機能です。このソースは誰でも読むことができますが、標準ライブラリの実装を読もうという人は(理由が無い限り)ほとんど居ないようですね。基本的に、これはC++0xの"move semantics"をライブラリ側で実装したものですので、言語自体がサポートするのに比べて多くの制限があります。VC8ではコンテナ(vector, deque, listなど)にO(1)のswapを持たせるためにテンプレートの魔法を駆使しました。その結果、コンテナのコンテナは元の要素のコピーを取ったり破壊したりせずにスワップするようになりました。(組み込み型に関してはスワップは効率が悪くなります。)


この機構をTR1の新しい型に対しても拡張しました。これは、独自のswap()実装を持つあらゆるTR1の型にご利益があります。shared_ptr/weak_ptr(参照カウントの操作を回避)、function(動的メモリ確保/開放を回避)、regex(FSM全体のコピーを回避)、match_results(vectorのコピーを回避)、unordered_set等(内部のテーブル等のコピーを回避)、array(これはO(1)で動くswap()を持ちませんが、swap_ranges()がありますので、O(1)なswapのある要素のarrayにはご利益があります)。


要するに、もしvector >がリアロケーションすることになっても、参照カウンタの上げ下げは起こらない、ということです。