CORBAを使ったプログラミングで、valuetypeのインスタンスをコピーしたい局面があったのですが、単に実体の=ではエラー(operator=がprivateで隠される)となってしまうので、その方法を調べてみました。
どうやら、valuetypeの基底クラスであるValueBaseで純粋仮想関数として宣言されたValueBase* _copy_value() をオーバーライドするのがあるべき姿のようです。
が、C++オープンソースCORBAの雄であるTAOが_copy_value()をサポートしておらず、また、_copy_value()仕様に対する問題点も指摘されています。
今回は状況を調査・整理してみました。
valuetypeの_copy_value
C++のvaluetypeについて書かれた資料は少ないのですが、以下の2つをあたりました。
OMGのC++言語マッピングの仕様から、_copy_valueの定義を確認
まず、§4.19.5 ValueBase and Reference Counting から、ValueBase型が提供する純粋仮想なリファレンスカウンティング関係関数として以下の定義が記述されています。
namespace CORBA { class ValueBase { public: : (中略) virtual ValueBase* _copy_value() = 0; :(略 }; }
以下筆者の粗い翻訳
_copy_value()
valuetypeインスタンスをディープコピーするのに使われる。コピーしたものは元のインスタンスとは何の関連も無く、ライフタイムも独立する。C++言語ではコバリアントな戻り値型を提供するので、派生クラスにおいて_copy_value関数の戻り値型を、ValueBase*型ではなく派生型のポインタとすることができる。しかし、コバリアントな戻り値型は商用C++コンパイラのすべてが提供するには至っていないので、派生クラスにおいて_copy_valueの戻り値型はValueBase*であってもよい。ORBの実装ではどちらの方法を採用しても適合する。現時点では、移植性の上でコバリアントな戻り値型を必須とせず、代わりにvaluetypeのコピーの最も派生した型にダウンキャストする。
書籍「Pure CORBA」におけるvaluetypeの_copy_valueの説明

- 作者: Fintan Bolton
- 出版社/メーカー: Sams
- 発売日: 2001/07/16
- メディア: ペーパーバック
- この商品を含むブログ (1件) を見る
- pp.497-498より筆者の粗い翻訳
値型「ValueName」を実装するために、C++では、プログラマが、生成されたOBV_ValueNameクラスを継承しなれけばならない。また、必要であればCORBA::DefaultValueRefCountBaseクラスを継承できる。リスト11.8に値型を実装するクラスValueNameImplの概要を示す。
// リスト11.8 class ValueNameImpl : public virtual OBV_ValueName, public virtual CORBA::DefaultValueRefCountBase { // IDLの操作・属性を実装する仮想関数をオーバーライド ... (略) // 標準 _copy_value() 関数をオーバーライド virtual CORBA::ValueBase* _copy_value(); };
valueオブジェクトのディープコピーを返却する_copy_value()関数は、CORBA::ValueBaseクラスから継承される。_copy_value()関数の実装は提供されなければならない。
TAOにおける_copy_value()の問題
さて、valuetypeのコピー実装方法が分かったので、TAOで_copy_value()を実装してみましたが、問題が発生しました。TAOのCORBA::ValueBaseクラスにおける_copy_valueが以下のようになっているのです。
class TAO_Valuetype_Export ValueBase { public: : (中略) // Reference counting. /// %! virtual CORBA::ValueBase* _copy_value (void) = 0; : (後略)
なんとコメントアウトされています。
omniORBにおける_copy_value()の実現
C++用CORBAフリー実装系御三家の一つ、omniORBにおける実現を調べてみました。まず、CORBA::ValueBaseにおける定義は、以下のようにOMG仕様通りです。
class ValueBase { public: : (中略) virtual ValueBase* _copy_value() = 0; : (後略)
次に、omniORBのIDLコンパイラでvaluetypeのIDLからC++コードを生成してみました。生成されたヘッダーファイルでは、
class ValueName : public virtual CORBA::ValueBase { public: : (中略) #ifdef OMNI_HAVE_COVARIANT_RETURNS virtual ValueName* _copy_value(); #else virtual CORBA::ValueBase* _copy_value(); #endif : (後略)
生成された実装ファイルでは、
: (前略) #ifdef OMNI_HAVE_COVARIANT_RETURNS ValueName* #else CORBA::ValueBase* #endif ValueName::_copy_value() { CORBA::ValueBase* _b; _b = _omni_ValueFactoryManager::create_for_unmarshal(_PD_repoId, 123456789U); ValueName* _v = ValueName::_downcast(_b); if (!_v) { CORBA::remove_ref(_b); OMNIORB_THROW(BAD_PARAM, BAD_PARAM_ValueFactoryFailure, CORBA::COMPLETED_NO); } _v->_PR_copy_state(this); return _v; } : (後略)
MICOにおける_copy_value()の実現
ついでに、MICO 2.3.13のコードも調べてみました。
namespace CORBA { class ValueBase { :(中略) public: :(中略) virtual ValueBase* _copy_value (); : (後略)
と、純粋仮想ではなくValueBase型で実装が提供されています。