(これは2010-11-23に書いた故OCNブログの記事を移植したものです)
MSXMLなどのCOMタイプ ライブラリを#importしたときなど、COMを扱うときによく見かけるのが、Visual C++ CRTヘルパーの _bstr_t クラスと _variant_t クラス (comutil.h) です。それぞれ、COMのBSTR文字列のラッパーと、VARIANT型のラッパーとなっています。
ただしC++プログラマーとしてはこれらがグローバル名前空間で定義されてやがることに殺意を覚えます。シンボル名がアンダースコアで始まっているのは、処理系依存のデータ型であることを誇示しているのか……
あとアンダースコアなしのエイリアス bstr_t
と variant_t
がtypedefじゃなく#defineなのも情けないです。これらのエイリアスは使わないほうがよいでしょう。MSの#define好きは異常*1。
似たようなラッパーはATL (atlcomcli.h) にも用意されていて、ATL::CComBSTR
とATL::CComVariant
が該当するのですが、ついでにATL::CComSafeArray
(atlsafe.h) なんかもあります。MFC専用だとCOleVariant
というのもあります。
なお、_variant_t
は、MFCライブラリでもたまに使われているのを見かけます(CMFCPropertyGridProperty::SetValue()/GetValue()とか)。
正直VC++ネイティブで文字列を扱う場合、他の環境への移植性を考慮しないで良いのであれば、迷わずCStringA/CStringW/CStringを使うのがベストです*2。そもそもテンプレート機能まである静的型付け言語C++で何が悲しくてVariantなんぞ使わないといけないのかとも思いますが、VBやスクリプト言語との相互運用を考慮して設計されたCOMデュアル インターフェイスの境界では、たとえ非効率でもBSTRやVARIANT、SAFEARRAYを使わざるを得ません。で、COMのBSTRは::SysAllocString()/::SysFreeString()、SAFEARRAYは::SafeArrayCreate()/::SafeArrayDestroy()でヒープ管理されるので、こういうRAIIラッパーがないと発狂するでしょう。ただ、ラッパークラスはCRTアロケータを使っていない時点で速度が出ない(とくに文字列の結合が毎回再割り当てを伴うために遅いらしい)し、下手な使い方をするとメモリーリークの原因になるので、COMのRAIIラッパーを使用する場合はCOM境界のみに限定するべきです。ちなみにATL::CComBSTR
はアタッチ・デタッチがやや特殊で、使い方を誤ると簡単にメモリーリークするらしいので、極力_bstr_t
を使ったほうが無難らしいです。
実装を確認してみたところ、一応 CComBSTR::operator&
にはアサーションが入っているので、デバッグビルドであれば誤った使い方をしたときに気付くはずです。