目次 前 次 PDF


OMG IDL文のC++へのマッピング

OMG IDL文のC++へのマッピング
この章では、OMG IDL文からC++へのマッピングについて説明します。
注意:
この章の一部の情報は、Object Management Group (OMG)の『Common Object Request Broker: C++ Language Mapping Specification』(1999年6月)から転載しています。OMGの許可を得て使用されています。
マッピング
以下では、OMG IDLからC++へのマッピングの次のトピックについて説明します。
また、次のトピックについても説明します。
データ型
各OMG IDLのデータ型は、C++のデータまたはクラスにマッピングされます。
基本データ型
表13-1に示すように、OMG IDL文の基本データ型は、CORBAモジュールのC++ typedefにマッピングされます。
 
 
注意:
長精度型(long)が64ビットのマシンでも、CORBA::Longの定義は32ビット整数を参照します。
複雑なデータ型
表13-2に、オブジェクト、擬似オブジェクト、およびユーザー定義型のマッピングを示します。
 
 
文字列およびUDTのマッピングの詳細は、以降のセクションを参照してください。
文字列
OMG IDLの文字列は、C++のchar *にマッピングされます。char *には、制限付き文字列と無制限文字列の両方がマッピングされます。C++のCORBA文字列は、NULLで終了し、char *の使用時には常に使用できます。
structなど、他のユーザー定義のの中に文字列がある場合は、CORBA::String_var型にマッピングされます。これにより、構造体内の各メンバーは自身のメモリーを管理できます。
文字列の割り当ておよび割当て解除には、CORBAクラスの次のメンバー関数を使用する必要があります。
注意:
string_alloc関数によってlen+1文字が割り当てられるので、結果として得られた文字列には後続のNULL文字の保持に十分なスペースを確保できます。
wchar
OMG IDLでは、任意の文字セットからワイド文字をエンコードするwcharデータ型を定義します。文字データと同じく、実装では任意のコード・セットを使用してワイド文字をエンコードします。ただし、転送にはほかの形式への変換が必要になる場合もあります。wcharのサイズは、実装によって異なります。
次に、wcharを定義する構文を示します。
<wide_char_type> ::= “wchar”
次に、wcharのサンプル・コードを示します。
wchar_t wmixed[256];
注意:
wcharおよびwstringデータ型を使用すると、ユーザーが記述するネイティブ言語でコンピュータと対話できます。日本語や中国語など、言語によっては一意の文字が多数ある言語もあります。このような文字セットは、1バイトの中に収まりません。マルチ・バイト文字セットをサポートするために様々なスキームが考案されていますが、まだ実用的なレベルには至っていません。ワイド文字とワイド文字列を使用すると、こういった複雑な文字セットとのやり取りが容易になります。
wstring
wstringデータ型は、ワイド文字NULLを除きwcharのシーケンスを表します。wstring型はstring型と似ていますが、その要素型がcharではなくwcharである点で異なります。wstringの実際の長さは実行時に設定されます。制限付き形式を使用する場合、長さは制限以下でなければなりません。
次に、wstringを定義する構文を示します。
<wide_string_type> ::= “wstring” “<” <positive_int_const> “>”
| “wstring
次に、wstringのサンプル・コードを示します。
CORBA::WString_var v_upper = CORBA::wstring_dup(wmixed);
wstring型は、unsigned long、char、string、doubleなどの型とまったく同様にビルドされます。これらの型は、パラメータとして直接使用したり、typedefで指定したり、構造体、シーケンス、ユニオン、配列などの作成に使用したりできます。
注意:
wcharおよびwstringデータ型を使用すると、ユーザーが記述するネイティブ言語でコンピュータと対話できます。日本語や中国語など、言語によっては一意の文字が多数ある言語もあります。このような文字セットは、1バイトの中に収まりません。マルチ・バイト文字セットをサポートするために様々なスキームが考案されていますが、まだ実用的なレベルには至っていません。ワイド文字とワイド文字列を使用すると、こういった複雑な文字セットとのやり取りが容易になります。
定数
OMG IDLの定数は、C++のconst定義にマッピングされます。次に、OMG IDL定義の例を示します。
// OMG IDL
const string CompanyName = “BEA Systems Incorporated”;
module INVENT
{
const string Name = “Inventory Modules”;
interface Order
{
const long MAX_ORDER_NUM = 10000;
};
};
上の定義は、次のようにC++にマッピングされます。
// C++
const char *const
CompanyName = “BEA Systems Incorporated”;
. . .
class INVENT
{
static const char *const Name;
. . .
class Order : public virtual CORBA::Object
{
static const CORBA::Long MAX_ORDER_NUM;
. . .
};
};
最上位の定数は、生成された.hインクルード・ファイルで初期化されます。ただし、モジュールとインタフェースの各定数は、生成されたクライアント・スタブ・モジュールで初期化されます。
次に、前の例で定義したMAX_ORDER_NUM定数への有効な参照の例を示します。
CORBA::Long accnt_id = INVENT::Order::MAX_ORDER_NUM;
Enum
OMG IDLのenumは、C++のenumにマッピングされます。次に、OMG IDL定義の例を示します。
// OMG IDL
module INVENT
{
enum Reply {ACCEPT, REFUSE};
}
上の定義は、次のようにC++にマッピングされます。
// C++
class INVENT
{
. . .
enum Reply {ACCEPT, REFUSE};
};
次に、前の例で定義した列挙への有効な参照の例を示します。次のように列挙を参照します。
INVENT::Reply accept_reply;
accept_reply = INVENT::ACCEPT;
構造体
OMG IDLの構造体は、C++の構造体にマッピングされます。
構造体に対して生成されるコードは、その構造体が固定長か可変長かによって異なります。固定長型と可変長型の詳細は、「固定長ユーザー定義型と可変長ユーザー定義型」という項を参照してください。
固定長構造体と可変長構造体
可変長構造体には、代入演算子メンバー関数が別にあり、2つの可変長構造体間の代入を処理します。
次に、OMG IDL定義の例を示します。
// OMG IDL
module INVENT
{
// Fixed-length
struct Date
{
long year;
long month;
long day;
};

// Variable-length
struct Address
{
string aptNum;
string streetName;
string city;
string state;
string zipCode;
};
};
上の定義は、次のようにC++にマッピングされます。
// C++
class INVENT
{
struct Date
{
CORBA::Long year;
CORBA::Long month;
CORBA::Long day;
};
struct Address
{
CORBA::String_var aptNum;
CORBA::String_var streetName;
CORBA::String_var city;
CORBA::String_var state;
CORBA::String_var zipCode;
Address &operator=(const Address &_obj);
};

};
メンバーのマッピング
構造体のメンバーは、適切なC++データ型にマッピングされます。基本データ型(longやshortなど)については、表13-1を参照してください。オブジェクト参照、擬似オブジェクト参照、および文字列については、メンバーは次の適切なvarクラスにマッピングされます。
その他のデータ型については、表13-2を参照してください。
生成される構造体にはコンストラクタがないため、メンバーは初期化されません。固定長構造体は、集約初期化子を使用して初期化できます。たとえば、次のようにします。
INVENT::Date a_date = { 1995, 10, 12 };
可変長メンバーの場合、自己管理型にマッピングします。この型には、メンバーを初期化するコンストラクタが含まれています。
Var
varクラスは、構造体に対して生成されます。詳細は、「varクラスの使い方」という項を参照してください。
Out
outクラスは、構造体に対して生成されます。詳細は、「outクラスの使い方」という項を参照してください。
ユニオン
OMG IDLのユニオンは、C++クラスにマッピングされます。C++クラスには次のものが含まれています。
次に、OMG IDL定義の例を示します。
// OMG IDL
union OrderItem switch (long)
{
case 1: itemStruct itemInfo;
case 2: orderStruct orderInfo;
default: ID idInfo;
};
上の定義は、次のようにC++にマッピングされます。
// C++
class OrderItem
{
public:
OrderItem();
OrderItem(const OrderItem &);
~OrderItem();

OrderItem &operator=(const OrderItem&);
void _d (CORBA::Long);
CORBA::Long _d () const;

void itemInfo (const itemStruct &);
const itemStruct & itemInfo () const;
itemStruct & itemInfo ();

void orderInfo (const orderStruct &);
const orderStruct & orderInfo () const;
orderStruct & orderInfo ();

void idInfo (ID);
ID idInfo () const;

. . .
};
デフォルトのユニオン・コンストラクタでは、ユニオンのデフォルト区別子の値が設定されていません。そのため、ユニオンの値を設定するまでは、すべてのユニオン・アクセサ・メンバー関数を呼び出すことができません。区別子は、_dメンバー関数でマッピングされる属性です。
ユニオン・メンバーのアクセサ・メンバー関数とモディファイア・メンバー関数のマッピング
ユニオンのメンバーごとに、アクセサ・メンバー関数とモディファイア・メンバー関数が生成されます。
前の例から抜粋した次のコードでは、2つのメンバー関数はIDメンバー関数に対して生成されています。
void idInfo (ID);
ID idInfo () const;
この例では、最初の関数(モディファイア)で区別子をデフォルト値に、ユニオンの値を指定のID値に設定しています。2番目の関数であるアクセサは、ユニオンの値を返します。
ユニオン・メンバーのデータによっては、モディファイア関数が追加生成されます。各データに対して生成されるメンバー関数は次のとおりです。
基本データ型 - short、long、unsigned short、unsigned long、float、double、char、boolean、およびoctet

次の例では、メンバー名basictypeで基本データ
の2つのメンバー関数を生成しています。

void basictype (TYPE); // modifier
TYPE basictype () const; // accessor

OMG IDLのデータからC++のデータTYPEへのマッピングについては、表13-1を参照してください。
オブジェクトおよび擬似オブジェクト

メンバー名が
objtypeのオブジェクト型およびTypecode型の場合、メンバー関数は次のように生成されます。

void objtype (TYPE); // modifier
TYPE objtype () const; // accessor

OMG IDLのデータ型からC++のデータ型TYPEへのマッピングについては、表13-1を参照してください。

モディファイア・メンバー関数では、指定されたオブジェクト参照引数の所有権を想定していません。代わりに、モディファイアはオブジェクト参照または擬似オブジェクト参照を複製します。リファレンスが不要になったときは、リファレンスを解放してください。
Enum

メンバー名がenumtypeのenum
TYPEの場合、メンバー関数は次のように生成されます。

void enumtype (TYPE); // modifier
TYPE enumtype () const; // accessor
文字列

文字列の場合、次に示すようにアクセサ関数が1つとモディファイア関数3つが生成されます。

void stringInfo (char *); // modifier 1
void stringInfo (const char *); // modifier 2
void stringInfo (const CORBA::String_var &); // modifier 3
const char * stringInfo () const; // accessor

最初のモディファイアでは、渡されたchar *パラメータの所有権を想定しており、ユニオンの値が変更されるかユニオンが破棄されたときに、ユニオンはこの文字列に対してCORBA::string_freeメンバー関数を呼び出します。

2番目と3番目のモディファイアでは、パラメータに渡されるか、または文字列varに格納されている指定の文字列をコピーします。

アクセサ関数は、ユニオンの内部メモリーへのポインタを戻します。また、このメモリーの解放を試行せず、ユニオンの値が変更されるかユニオンが破棄された後は、このメモリーにアクセスしません。
構造体、ユニオン、シーケンスおよびAny

これらのデータ型の場合、次に示すようにモディファイア関数とアクセサ関数は、
typeへの参照で生成されます。

void reftype (TYPE &); // modifier
const
TYPE & reftype () const; // accessor
TYPE & reftype (); // accessor

モディファイア関数は、入力パラメータtypeの所有権を想定していません。かわりに、関数はデータをコピーします。
配列

配列の場合、次に示すように、モディファイア・メンバー関数は配列ポインタを受け付け、アクセサは配列スライスへのポインタを返します。

void arraytype (TYPE); // modifier
TYPE_slice * arraytype () const; // accessor

モディファイア関数は、入力パラメータtypeの所有権を想定していません。かわりに、関数は配列をコピーします。
Var
varクラスは、ユニオンに対して生成されます。詳細は、「varクラスの使い方」という項を参照してください。
Out
outクラスは、ユニオンに対して生成されます。詳細は、「outクラスの使い方」という項を参照してください。
メンバー関数
アクセサとモディファイアに加えて、型TYPEのOMG IDLユニオンに対してswitch (long)区別子で次のメンバー関数が生成されます。
TYPE();
ユニオンのデフォルトのコンストラクタです。この関数ではデフォルトの区別子が設定されないため、ユニオンの値を設定するまではユニオンにアクセスできません。
TYPE( const TYPE & From);
このコピー・コンストラクタは、指定のユニオンをディープ・コピーします。ユニオン・パラメータ内のデータがコピーされます。From引数には、コピーするユニオンを指定します。
~TYPE();
このデストラクタは、ユニオンに関連付けられたデータを解放します。
TYPE &operator=(const TYPE & From);
この代入演算子は、指定のユニオンをコピーします。現在のユニオン内の既存の値が解放されます。From引数には、コピーするユニオンを指定します。
void _d (CORBA::Long Discrim);
このモディファイア関数は、ユニオン区別値の値を設定します。Discrim引数には、新しい区別値を指定します。引数のデータ型は、ユニオンのswitch文で指定したOMG IDLのデータ型で決まります。OMG IDLおよびC++の各データ型については、表13-1を参照してください。
この関数は、同じユニオン・メンバー内の値に区別値を設定する場合にのみ使用します。この関数を使用して、ユニオン・メンバーを別のユニオン・メンバーに暗黙的に切り替えることはできません。
これらの制約については、次のコードを参照してください。
union U switch(long) {
case 1:
case 2:
short s;
case 3:
int it;
};

short st;
U u;
u.s(1296); // member "s" selected
st = u.s(); // st == 1296
u._d(2); // OK: member "s" still selected
st = u.s(); // st == 1296
u._d(3); // BAD_PARAM: selecting a different member
ユニオンの新しいインスタンスで_d()モディファイアが呼び出されると、Tuxedo C++の「暗黙的な切替」の制約が緩和されます。この場合、例外はスローされず、ユニオンへの影響はありません。
U u2;
u2._d(1); // no exception, union is unchanged
st = u2.s(); // error! accessing an uninitialized union
u2.it(1296); // OK: member "it" now selected
CORBA::Long _d () const;
この関数は、現在の区別値を返します。戻り値のデータ型は、ユニオンのswitch文で指定したOMG IDLのデータ型で決まります。OMG IDLおよびC++の各データ型については、表13-1を参照してください。
シーケンス
OMG IDLのシーケンスは、C++クラスにマッピングされます。C++クラスには次のものが含まれています。
各シーケンスには、次のものがあります。
シーケンス要素にアクセスしたり、シーケンス要素を変更するOperator[]関数
要素にアクセスする場合、事前に長さを設定しておく必要があります
次に、OMG IDL定義の例を示します。
// OMG IDL
module INVENT
{
. . .
typedef sequence<LogItem> LogList;
}
上の定義は、次のようにC++にマッピングされます。
// C++
class LogList
{
public:
// Default constructor
LogList();
// Maximum constructor
LogList(CORBA::ULong _max);
// TYPE * data constructor
LogList
(
CORBA::ULong _max,
CORBA::ULong _length,
LogItem *_value,
CORBA::Boolean _relse = CORBA_FALSE
);
// Copy constructor
LogList(const LogList&);
// Destructor
~LogList();
LogList &operator=(const LogList&);
CORBA::ULong maximum() const;
void length(CORBA::ULong);
CORBA::ULong length() const;
LogItem &operator[](CORBA::ULong _index);
const LogItem &operator[](CORBA::ULong _index) const;
static LogItem *allocbuf(CORBA::ULong _nelems);
static void freebuf(LogItem *);
};
};
シーケンス要素のマッピング
operator[]関数は、シーケンス要素へのアクセスまたはシーケンス要素の変更に使用します。この演算子は、シーケンス要素にリファレンスを返します。OMG IDLのベース・タイプは、C++の適切なデータ型にマッピングされます。
基本データ型については、表13-1を参照してください。オブジェクト参照、TypeCodeリファレンス、および文字列の場合、ベース・タイプは生成された_ForSeq_varクラスにマッピングされます。_ForSeq_varクラスは、文字列またはシーケンス内に格納されたオブジェクトを更新する機能を備えています。このクラスには、対応するvarクラスと同じメンバー関数とシグネチャがあります。ただし、_ForSeq_varクラスは、シーケンス・コンストラクタのreleaseパラメータの設定に従います。ほかのクラスとの相違点は、_ForSeq_varクラスの場合、ユーザーがReleaseフラグを指定できるので、メモリーの解放を制御できることです。
その他のデータ型については、表13-2を参照してください。
Var
varクラスは、シーケンスに対して生成されます。詳細は、「varクラスの使い方」という項を参照してください。
Out
outクラスは、シーケンスに対して生成されます。詳細は、「outクラスの使い方」という項を参照してください。
メンバー関数
次では、ベース・タイプがTYPEで指定のOMG IDLシーケンスがSEQの場合に、生成されるシーケンス・クラスのメンバー関数について説明します。
SEQ ();
シーケンスのデフォルトのコンストラクタです。長さは、0 (ゼロ)に設定されます。シーケンスが無制限の場合、最大値も0 (ゼロ)に設定されます。シーケンスが制限されている場合、最大値はOMG IDLの型で指定され、変更することはできません。
SEQ (CORBA::ULong Max);
このコンストラクタは、シーケンスが無制限の場合にのみ存在します。この関数は、シーケンスの長さを0 (ゼロ)に設定し、バッファの最大値を指定の値に設定します。Max引数には、シーケンスの最大長を指定します。
SEQ (CORBA::ULong Max, CORBA::ULong Length, TYPE * Value,
CORBA::Boolean Release);
このコンストラクタは、シーケンスの最大値、長さおよび要素を設定します。シーケンスが破棄されたときに要素を解放するかどうかは、Releaseフラグで指定します。各引数について次に説明します。
Max
シーケンスの最大値。制限付きシーケンスでは、この引数はありません。
Length
シーケンスの現在の長さ。制限付きシーケンスの場合、この値はOMG IDLの型で指定した最大値より小さい値を指定する必要があります。
Value
シーケンスの要素を格納するバッファへのポインタ。
Release
要素を解放するかどうかを指定します。このフラグの値がCORBA_TRUEの場合、シーケンスはValue引数が指すバッファの所有権を想定します。ReleaseフラグがCORBA_ TRUEの場合、このバッファはallocbufメンバー関数で割り当てる必要があります。これは、シーケンスの破棄時に、このバッファをfreebufメンバー関数で解放するためです。
SEQ(const S& From);
このコピー・コンストラクタは、指定の引数からシーケンスをディープ・コピーします。From引数には、コピーするシーケンスを指定します。
~SEQ();
このデストラクタは、シーケンスを解放します。また、Releaseフラグの値によっては、シーケンス要素を解放する場合もあります。
SEQ& operator=(const SEQ& From);
この代入演算子は、指定のシーケンス引数からシーケンスをディープ・コピーします。現在のシーケンスのReleaseフラグがCORBA_TRUEの場合、現在のシーケンスにある既存の要素はすべて解放されます。From引数には、コピー元のシーケンスを指定します。
CORBA::ULong maximum( ) const;
この関数は、シーケンスの最大値を返します。制限付きシーケンスの場合、これはOMG IDLの型に設定された値です。無制限シーケンスの場合、これはシーケンスの現在の最大値です。
void length(CORBA::ULong Length);
この関数は、シーケンスの現在の長さを設定します。Length引数には、シーケンスの新しい長さを指定します。シーケンスが無制限で新しい長さが現在の最大値を超える場合、バッファが再割り当てされ、要素が新しいバッファにコピーされます。新しい長さが最大値を超える場合、最大値は新しい長さに設定されます。
制限付きシーケンスの場合は、最大値を超える値には長さを設定できません。
CORBA::ULong length() const;
この関数は、シーケンスの現在の長さを返します。
TYPE & operator[](CORBA::ULong Index);
const
TYPE & operator[](CORBA::ULong Index) const;
前述のアクセサ関数は、指定の索引でシーケンス要素への参照を返します。Index引数には、戻り値となる要素の索引を指定します。この索引は、現在のシーケンスの長さを超えることはできません。長さは、TYPE *コンストラクタまたはlength(CORBA::ULong)モディファイアで設定済ある必要があります。TYPEがオブジェクト参照、TypeCodeリファレンス、または文字列の場合、戻り値の型はForSeq_varクラスになります。
static TYPE * allocbuf(CORBA::ULong NumElems);
この静的関数は、TYPE *コンストラクタで使用されるバッファを割り当てます。NumElems引数には、バッファ内の割り当てる要素数を指定します。バッファの割当てができない場合、NULLが返されます。
releaseがCORBA_TRUEに設定されていて、このバッファがTYPE *コンストラクタに渡されない場合は、freebufメンバー関数で解放する必要があります。
static void freebuf(TYPE * Value);
この静的関数は、allocbuf関数で割り当てられたTYPE *シーケンス・バッファを解放します。Value引数には、allocbuf関数で割り当てられたTYPE *バッファを指定します。0(ゼロ)ポインタは無視されます。
配列
OMG IDLの配列は、C++の配列定義にマッピングされます。次に、OMG IDL定義の例を示します。
// OMG IDL
module INVENT
{
. . .
typedef LogItem LogArray[10];
};
上の定義は、次のようにC++にマッピングされます。
// C++
module INVENT
{
. . .
typedef LogItem LogArray[10];
typedef LogItem LogArray_slice;
static LogArray_slice * LogArray_alloc(void);
static void LogArray_free(LogArray_slice *data);

};
配列のスライス
配列のスライスとは、元の配列の最初のサイズを除いたすべてのサイズを持つ配列のことです。配列で生成されるクラスのメンバー関数は、スライスへのポインタを使用して、配列へのポインタを返します。スライスごとにtypedefが生成されます。
次に、OMG IDL定義の例を示します。
// OMG IDL
typedef LogItem LogMultiArray[5][10];
上の定義は、次のようにC++にマッピングされます。
// C++
typedef LogItem LogMultiArray[5][10];
typedef LogItem LogMultiArray_slice[10];
1次元配列がある場合、配列スライスは単なる型です。たとえば、1次元配列がlongの場合、配列スライスはCORBA::Longデータ型になります。
配列要素のマッピング
OMG IDLの配列の型は、構造体と同じ方法でC++の配列要素型にマッピングされます。詳細は、「メンバーのマッピング」という項を参照してください。
Var
varクラスは、配列に対して生成されます。詳細は、「varクラスの使い方」という項を参照してください。
Out
outクラスは、配列に対して生成されます。詳細は、「outクラスの使い方」という項を参照してください。
割当てメンバー関数
配列ごとに静的関数が2つあります。配列を割り当てるためのものと、割当てを解除するためのものです。指定のOMG IDLの型TYPEの場合、割当てルーチンと割当て解除ルーチンは次のとおりです。
static TYPE_slice * TYPE_alloc(void);
この関数は、TYPE配列を割り当て、割当て済TYPE配列へのポインタを返します。配列を動的に割り当てることができない場合、0(ゼロ)を返します。
static void TYPE_free(TYPE_slice * Value);
この関数は、動的に割り当てられたTYPE配列を解放します。Value引数は、解放元の動的に割り当てられたTYPE配列へのポインタです。
例外
OMG IDLの例外は、C++クラスにマッピングされます。C++クラスには次のものが含まれています。
生成されるクラスは可変長構造体と似ています。ただし、このクラスは初期化を簡単にするためのコンストラクタ、およびUserExceptionの型を判別するための静的_narrowメンバー関数が追加されている点で異なります。
次に、OMG IDL定義の例を示します。
// OMG IDL
module INVENT
{
exception NonExist
{
ID BadId;
};
};
上の定義は、次のようにC++にマッピングされます。
// C++
class INVENT
{
. . .
class NonExist : public CORBA::UserException
{
public:
static NonExist * _narrow(CORBA::Exception_ptr);
NonExist (ID _BadId);
NonExist ();
NonExist (const NonExist &);
~NonExist ();
NonExist & operator=(const NonExist &);
void _raise ();
ID BadId;
};
};
Exceptionクラスの属性(データ・メンバー)はパブリックなので、直接アクセスできます。
メンバーのマッピング
例外のメンバーは、構造体と同じ方法でマッピングされます。詳細は、「メンバーのマッピング」を参照してください。
例外メンバーはすべて、C++ではパブリック・データなので、直接アクセスできます。
Var
varクラスは、例外に対して生成されます。詳細は、「varクラスの使い方」という項を参照してください。
Out
outクラスは、例外に対して生成されます。詳細は、「outクラスの使い方」という項を参照してください。
メンバー関数
指定のOMG IDL例外TYPEの場合、生成されるメンバー関数は次のとおりです。
static TYPE * _narrow(CORBA::Exception_ptr Except);
この関数は、例外がTYPE例外にナロー変換できる場合に、TYPE例外へのポインタを返します。例外がナロー変換できない場合は、0(ゼロ)を返します。TYPEポインタは、新しいクラスへのポインタではなく、 元の例外ポインタへの型付きポインタです。これは、Exceptパラメータが有効なかぎりにおいて有効です。
TYPE ( );
例外のデフォルトのコンストラクタです。固定長メンバーに対しては、メンバーの初期化は実行されません。可変長メンバーの場合、自己管理型にマッピングします。この型には、メンバーを初期化するコンストラクタが含まれています。
TYPE(member-parameters);
このコンストラクタには、例外のメンバーごとに引数があります。このコンストラクタは、各引数をコピーし、どの引数についてもメモリーの所有権を想定しません。前の例によると、コンストラクタのシグネチャは次のとおりです。
NonExist (ID _BadId);
例外のメンバーごとに引数が1つあります。型およびパラメータ渡しメカニズムは、Any挿入演算子と同じです。Any挿入演算子の詳細は、「Anyへの挿入」という項を参照してください。
TYPE (const TYPE & From);
このコピー・コンストラクタは、指定のTYPE例外引数からデータをコピーします。From引数には、コピー元の例外を指定します。
~TYPE ();
このデストラクタは、例外に関連付けられたデータを解放します。
TYPE & operator=(const TYPE & From);
この代入演算子は、指定のTYPE例外引数からデータをコピーします。From引数には、コピー元の例外を指定します。
void _raise ();
この関数によって、例外インスタンスが自己に対してスローされます。catch句は、
派生した型で例外インスタンスを捕捉できます。
擬似オブジェクトのC++へのマッピング
CORBA擬似オブジェクトは、通常のCORBAオブジェクトまたはサーバーレス・オブジェクトとして実装できます。CORBA仕様における、これらの戦略の基本的な違いは次のとおりです。
サーバーレス・オブジェクト型はCORBA::Objectを継承しません。
サーバーレス・オブジェクトへの参照は、計算コンテキスト(たとえば、アドレス空間)全体にわたって有効であるとはかぎりません。かわりに、サーバーレス・オブジェクトへの参照をパラメータとして渡すと、オブジェクトのコピーを元のオブジェクトと機能が同じ独立したものとして作成して、参照の受取り側ではそのコピーを使用するようにすることもできます。これをサポートするには、サーバーレス・オブジェクトの本来なら非表示である表現用プロパティ(データ・レイアウトなど)がORBに認識されるようにします。これを実現するための仕様は、この章には含まれていません。サーバーレス・オブジェクトがORBに認識されるようにするのは実装詳細です。
この章では、すべての擬似オブジェクト型を対象とする標準のマッピング・アルゴリズムについて説明します。これにより、9種類のCORBA擬似オブジェクト型ごとのマッピングについて、説明が断片的にならずに済み、CORBAの将来のリビジョンで提供される可能性のある擬似オブジェクト型にも対応できます。また、Cマッピングの表現に依存せずに、C互換の表現に依存した実装を実現することができます。
使用方法
このマッピングでは、C-PIDLではなく、拡張を施した完全なOMG IDLを使用して、サーバーレス・オブジェクト型を記述します。擬似オブジェクト型のインタフェースは、次の例外を除き、通常のOMG IDLインタフェースと同じ規則に従います。
先頭にキーワードpseudoが付きます。
通常の場合ではOMG IDLで許可されていない、他のサーバーレス・オブジェクト型1を宣言で参照する場合があります。
pseudo接頭辞は、そのインタフェースが通常の方法またはサーバーレスの方法のどちらかで実装されることを示します。つまり、以降のセクションで説明する規則か、またはこの章で説明する通常のマッピング規則のどちらかを適用することになります。
マッピング規則
サーバーレス・オブジェクトは、このセクションで概説する相違点を除いて、通常のインタフェースと同じ方法でマッピングされます。
サーバーレス・オブジェクト型を表すクラスは、CORBA::Objectのサブクラスではありません。また、他のC++クラスのサブクラスである必要はありません。したがって、Object::create_requestなどの操作を必ずしもサポートしません。
サーバーレス・オブジェクト型のTを表す各クラスの場合、次の関数のオーバーロードの各バージョンがCORBAネームスペースで提供されます。
// C++
void release(T_ptr);
Boolean is_nil(T_ptr p);
サブクラスは実装で提供できます。ただし、マッピングされたC++クラスは、ユーザーが容易にサブクラス化できるという保証はありません。実装では、サブクラスに適用されない可能性がある内部表現およびトランスポート形式を想定できます。
サーバーレス・オブジェクト型を表すクラスのメンバー関数は、必ずしも通常のメモリー管理規則に従っているとはかぎりません。これは、CORBA::NVListなどの一部のサーバーレス・オブジェクトが、本質的に他のサーバーレス・オブジェクトのいくつかのレベルのコンテナでしかない場合があるためです。格納されたサーバーレス・オブジェクトのアクセサ関数から返された値を、呼出し側が明示的に解放しなければならないということは、本来の目的とは反対の使い方になってしまいます。
マッピングのその他すべての要素は同一です。具体的には次のとおりです。
サーバーレス・オブジェクトへの参照の型であるT_ptrは、単にT*のtypedefである必要はありません。
// C++
static T_ptr _duplicate(T_ptr p);
static T_ptr _nil();
_duplicateの有効な実装では、単純に引数を返すか、または新しいインスタンスへの参照を作成します。個別に実装を行うことで、動作の確実性が高くなることがあります。
C PIDLマッピングとの関係
すべてのサーバーレス・オブジェクト・インタフェースおよびそれらを利用する宣言は、Cマッピングに類似しています。マッピングされたC++クラスは、Cマッピング用に選択した表現と互換性のある表現を使用して実装できますが、必須ではありません。C-PIDLとC++ PIDLでの擬似オブジェクト仕様の違いは次のとおりです。
C++ PIDLでは、その他の指定がないかぎり、releaseは、関連付けられたCマッピングのfreeおよびdelete操作の役割を果します。
後の項では、各擬似インタフェースとそのC++マッピングを簡単に説明し、リストにまとめています。以下で定義が行われない型も含め、詳細は、このマニュアルの関連する項を参照してください。
Typedef
OMG IDLのtypedefは、C++のtypedefにマッピングされます。OMG IDLのデータ型によっては、さらにtypedefおよびメンバー関数を定義できます。データ型ごとに生成されるコードは次のとおりです。
基本データ型は単純なtypedefにマッピングされます。たとえば、次のようになります。
// OMG IDL
typedef long ID;
// C++
typedef CORBA::Long ID;
文字列のtypedefは単純なtypedefにマッピングされます。たとえば、次のようになります。
// OMG IDL
typedef string IDStr;
// C++
typedef char * IDStr;
オブジェクト、インタフェース、およびTypeCodeは、4つのtypedefにマッピングされます。たとえば、次のようになります。
// OMG IDL
typedef Item Intf;
// C++
typedef Item Intf;
typedef Item_ptr Intf_ptr;
typedef Item_var Intf_var;
typedef Item_ptr & Intf _out;
UDTは3つのtypedefにマッピングされます。たとえば、次のようになります。
// OMG IDL
typedef LogList ListRetType;
// C++
typedef LogList ListRetType;
typedef LogList_var ListRetType_var;
typedef LogList_out & ListRetType_out;
配列は、メモリーを割り当てたり解放するために4つのtypedefと静的メンバー関数にマッピングされます。たとえば、次のようになります。
// OMG IDL
typedef LogArray ArrayRetType;
// C++
typedef LogArray ArrayRetType;
typedef LogArray_var ArrayRetType_var;
typedef LogArray_forany ArrayRetType_forany;
typedef LogArray_slice ArrayRetType_slice;
ArrayRetType_slice * ArrayRetType_alloc();
void ArrayRetType_free(ArrayRetType_slice *);
インタフェースの実装
OMG IDLの操作は、C++のメンバー関数にマッピングされます。
メンバー関数の名前は操作の名前です。操作とは、インタフェース・クラスとスタブ・クラスの両方にあるメンバー関数のことです。インタフェース・クラスは仮想クラスです。一方、スタブ・クラスは仮想クラスを継承し、クライアント・アプリケーション・スタブのメンバー関数のコードを格納します。オブジェクト参照に対して操作を呼び出すと、対応するスタブ・メンバー関数に含まれているコードが実行されます。
次に、OMG IDL定義の例を示します。
// OMG IDL
module INVENT
{
interface Order
{
. . .
ItemList modifyOrder (in ItemList ModifyList);
};
};
上の定義は、次のようにC++にマッピングされます。
// C++
class INVENT
{
. . .
class Order : public virtual CORBA::Object
{
. . .
virtual ItemList * modifyOrder (
const ItemList & ModifyList) = 0;
};
};
class Stub_Order : public Order
{
. . .
ItemList * modifyOrder (
const ItemList & ModifyList);
};
生成されたクライアント・アプリケーション・スタブには、スタブ・クラスに対して生成された次のコードが格納されます。
// ROUTINE NAME:    INVENT::Stub_Order::modifyOrder
//
// FUNCTIONAL DESCRIPTION:
//
// Client application stub routine for operation
// modifyOrder.
// (Interface : Order)
INVENT::ItemList * INVENT::Stub_Order::modifyOrder (
const INVENT::ItemList & ModifyList)
{
. . .
}
引数のマッピング
操作の各引数は、表13-1および表13-2で説明した、対応するC++の型にマッピングされます。
操作での引数のパラメータ渡しモードについては、表13-7および表13-8を参照してください。
操作の実装
実装メンバー関数のシグネチャは、OMG IDL操作のマップされたシグネチャです。クライアント側と異なり、サーバー側のマッピングでは、関数ヘッダーに適切な例外(throw)指定を含める必要があります。これにより、いつ無効な例外が発生したかをコンパイラで検出できるようになります。これは、ローカルC++からC++ライブラリへの呼出しを行う場合に必要です。この作業を行わない場合、呼出しでは有効な例外をチェックするラッパーを通過してしまいます。例:
// IDL
interface A
{
exception B {};
void f() raises(B);
};
// C++
class MyA : public virtual POA_A
{
public:
void f() throw(A::B, CORBA::SystemException);
...
};
すべての操作および属性が原因でCORBAシステム例外はスローされるため、操作にraises句がない場合でも、すべての例外指定でCORBA::SystemExceptionを含める必要があります。
メンバー関数内で、このポインタはクラスの定義に従って実装オブジェクトのデータを参照します。データへのアクセスに加えて、メンバー関数は同じクラスに定義されている別のメンバー関数を暗黙的に呼び出す場合があります。たとえば、次のようになります。
// IDL
interface A
{
void f();
void g();
};
 
// C++
class MyA : public virtual POA_A
{
public:
void f() throw(SystemException);
void g() throw(SystemException);
private:
long x_;
};

void
MyA::f() throw(SystemException)
{
this->x_ = 3;
this->g();
}
ただし、この方法でサーバント・メンバー関数が呼び出されるときは、CORBAオブジェクトの操作の実装としてではなく、単純にC++のメンバー関数として呼び出されています。このような場合、POA_Currentオブジェクトで使用可能な情報はすべて、メンバー関数の呼出し自体ではなく、C++メンバー関数の呼出しを実行したCORBAリクエストの呼出しを参照します。
オブジェクトからのスケルトンの派生
既存の一部のORB実装では、各スケルトン・クラスは対応するインタフェース・クラスから派生します。たとえば、インタフェースがMod::Aの場合、スケルトン・クラスPOA_Mod::AMod::Aから派生します。したがって、これらのシステムでは、標準のC++派生ベースの変換規則によって暗黙的にサーバントをオブジェクト参照で取得できます。
// C++
MyImplOfA my_a; // declare impl of A
A_ptr a = &my_a; // obtain its object reference
// by C++ derived-to-base conversion
このようなコードは、ORB準拠の実装でサポートできますが、必須ではないため、移植性がありません。移植性のある同等のコードでは、実装オブジェクトで_this()を呼び出し、未登録の場合は暗黙的にそれを登録して、そのオブジェクト参照を取得します。
// C++
MyImplOfA my_a; // declare impl of A
A_ptr a = my_a._this(); // obtain its object reference
PortableServer関数
POAに登録されたオブジェクトでは、オブジェクト識別子としてオクテット、特にPortableServer::POA::ObjectId型のシーケンスを使用します。ただし、C++のプログラマはオブジェクト識別子として文字列を使用することが多いため、C++マッピングでは、文字列のObjectIdへの変換、またはその逆の変換を行ういくつかの変換関数が用意されています。
// C++
namespace PortableServer
{
char* ObjectId_to_string(const ObjectId&);

ObjectId* string_to_ObjectId(const char*);
}
上記の関数は、パラメータ渡しおよびメモリー管理について、標準のC++マッピングの規則に準拠しています。
ObjectIdを文字列に変換したときに、文字列に正しくない文字(NULLなど)が生成された場合は、最初の2つの関数によってCORBA::BAD_PARAM例外がスローされます。
モジュール
OMG IDLのモジュールは、C++クラスにマッピングされます。モジュールに格納されるオブジェクトは、このC++クラスの中で定義します。インタフェースと型もクラスにマッピングされるため、ネストされたC++クラスが生成されます。
次に、OMG IDL定義の例を示します。
// OMG IDL
module INVENT
{
interface Order
{
. . .
};
};
上の定義は、次のようにC++にマッピングされます。
// C++
class INVENT
{
. . .
class Order : public virtual CORBA::Object
{
. . .
}; // class Order
}; // class INVENT
複数のモジュールをネストすると、複数のネストされたクラスが生成されます。モジュール内のものは、モジュール・クラスに含められます。インタフェース内のものは、インタフェース・クラスに含められます。
OMG IDLでは、モジュール、インタフェースおよび型を同じ名前にすることができます。ただし、C++言語のファイルを生成するときは、同じ名前にできません。この制限が必要になるのは、OMG IDL名は同じ名前のネストされたC++クラスに生成されるのですが、これがC++コンパイラではサポートされていないためです。
注意:
インタフェース
OMG IDLのインタフェースは、C++クラスにマッピングされます。このクラスは、OMG IDLインタフェース内にある操作、属性、定数、およびユーザー定義の型(UDT)を格納します。
インタフェースINTFの場合、生成されるインタフェース・コードには、次の項目が格納されます。
_duplicate静的メンバー関数
_narrow静的メンバー関数
_nil静的メンバー関数
次に、OMG IDL定義の例を示します。
// OMG IDL
module INVENT
{
interface Order
{
void cancelOrder ();
};
};
上の定義は、次のようにC++にマッピングされます。
// C++
class INVENT
{
. . .
class Order;
typedef Order * Order_ptr;
class Order : public virtual CORBA::Object
{
. . .
static Order_ptr _duplicate(Order_ptr obj);
static Order_ptr _narrow(CORBA::Object_ptr obj);
static Order_ptr _nil();
virtual void cancelOrder () = 0;
. . .
};
};
オブジェクト参照の型、静的メンバー関数、UDT、操作、および属性については、以降のセクションを参照してください。
生成される静的メンバー関数
ここでは、インタフェースINTFに対して生成される、_duplicate, _narrow、および_nilの各静的メンバー関数について詳細に説明します。
static INTF_ptr _duplicate (INTF_ptr Obj)
この静的メンバー関数は、既存のINTFオブジェクト参照を複製して、新しいINTFオブジェクト参照を返します。新しいINTFオブジェクト参照は、CORBA::releaseメンバー関数を呼び出して解放する必要があります。エラーが発生した場合、nil INTFオブジェクトへのリファレンスが返されます。引数Objには、複製元のオブジェクト参照を指定します。
static INTF_ptr _narrow (CORBA::Object_ptr Obj)
この静的メンバー関数は、既存のCORBA::Object_ptrオブジェクト参照に付与される、新しいINTFオブジェクト参照を返します。Object_ptrオブジェクト参照は、CORBA::ORB::string_to_objectメンバー関数を呼び出して作成されているか、または操作からパラメータとして返されています。
INTF_ptrオブジェクト参照は、INTFオブジェクト、またはINTFオブジェクトを継承するオブジェクトと対応している必要があります。新しいINTFオブジェクト参照は、CORBA::releaseメンバー関数を呼び出して解放する必要があります。引数Objには、INTFオブジェクト参照にナロー変換されるオブジェクト参照を指定します。Objパラメータは、このメンバー関数では変更されません。また、不要になったときは解放してください。ObjINTFオブジェクト参照にナロー変換できない場合は、INTF nilオブジェクト参照が返されます。
static INTF_ptr _nil ( )
この静的メンバー関数は、INTFインタフェースの新しいnilオブジェクト参照を返します。新しいリファレンスはCORBA::releaseメンバー関数を呼び出して解放する必要はありません。
オブジェクト参照の型
インタフェース・クラス(INTF)は仮想クラスです。CORBA標準では、次の処理は許可されていません。
かわりに、オブジェクト参照の型、INTF_ ptrクラス、またはINTF_varクラスのいずれかを使用します。
オブジェクト参照を取得するには、_narrow静的メンバー関数を使用します。これらのクラスで操作を呼び出すには、矢印演算子(->)を使用します。
INTF_varクラスは、INTF_varクラスがスコープをはずれるか、または再割り当てされるときに、オブジェクト参照を自動的に解放することでメモリー管理を簡単にします。変数の型は、多くのUDTに対して生成されます。「varクラスの使い方」では、変数の型について説明しています。
属性
OMG IDLの読取り専用属性は、属性値を返すC++関数にマッピングされます。読取り/書込み属性は、2つのオーバーロードC++関数にマッピングされます。1つは属性値を返すためのもので、もう1つは属性値を設定するためのものです。オーバーロード・メンバー関数の名前は、属性の名前です。
属性は、操作が生成される場合と同じ方法で生成されます。これらは、仮想クラスとスタブ・クラスの両方に定義します。次に、OMG IDL定義の例を示します。
// OMG IDL
module INVENT
{
interface Order
{
. . .
attribute itemStruct itemInfo;
};
};
上の定義は、次のようにC++にマッピングされます。
// C++
class INVENT
{
. . .
class Item : public virtual CORBA::Object
{
. . .
virtual itemStruct * itemInfo ( ) = 0;
virtual void itemInfo (
const itemStruct & itemInfo) = 0;
};
};
class Stub_Item : public Item
{
. . .
itemStruct * itemInfo ();
void itemInfo (
const itemStruct & itemInfo);
};
生成されたクライアント・アプリケーション・スタブには、スタブ・クラスに対して生成された次のコードが格納されます。
// ROUTINE NAME: INVENT::Stub_Item::itemInfo
//
// FUNCTIONAL DESCRIPTION:
//
// Client application stub routine for attribute
// INVENT::Stub_Item::itemInfo. (Interface : Item)
INVENT::itemStruct * INVENT::Stub_Item::itemInfo ( )
{
. . .
}
//
// ROUTINE NAME: INVENT::Stub_Item::itemInfo
//
// FUNCTIONAL DESCRIPTION:
//
// Client application stub routine for attribute
// INVENT::Stub_Item::itemInfo. (Interface : Item)
void INVENT::Stub_Item::itemInfo (
const INVENT::itemStruct & itemInfo)
{
}
引数のマッピング
属性は、属性値を返す操作と属性を設定する操作の2つの操作と等価です。たとえば、前述のitemInfo属性は、次のものと同じです。
void itemInfo (in itemStruct itemInfo);
itemStruct itemInfo ();
属性の引数マッピングは、操作引数のマッピングと同じです。属性は、表13-1および表13-2で説明しているように、対応するC++型にマッピングされます。操作での引数のパラメータ渡しモードについては、表13-7および表13-8を参照してください。
Any型
OMG IDLのanyは、CORBA::Anyクラスにマッピングされます。CORBA::Anyクラスは、型保障の方法でC++の型を処理します。
型付き値の処理
一致しないTypeCodeや値でanyが作成される可能性を低くするには、C++関数のオーバーロード機能を使用します。具体的には、OMG IDL仕様の特定の型ごとに、その型の値を挿入および抽出するためのオーバーロード関数が用意されています。ネームスペースの純粋さが損なわれるのを完全に防ぐには、これらの関数にオーバーロード演算子を使用します。これらの関数については以下で詳細に説明しますが、特徴としては、anyに挿入またはanyから抽出される値のC++の型によって適切なTypeCodeが示されるという点です。
後述する型保障anyインタフェースはC++関数のオーバーロードに基づいているため、OMG IDL仕様から生成されるC++の型は別々のものである必要があります。ただし、この要件が満たされない特別な場合があります。
文字列が制限付きか無制限かに関係なく、文字列はすべてchar*にマッピングされます。そのため、制限付き文字列値でanyを作成または設定する方法が別に必要となります。この方法については、「Boolean、Octet、Char、および制限付き文字列の識別」を参照してください。
Anyへの挿入
型保障の方法でanyの値を設定できるようにするために、OMG IDLの型Tごとに次のオーバーロード演算子関数が個別に用意されています。
// C++
void operator<<=(Any&, T);
この関数のシグネチャでは、次の型があれば十分です。通常、これらの型は値によって渡されます。
Short, UShort, Long, ULong, Float, Double
型Tの値が大きすぎて完全に値を渡すことができない場合、次の2つの形式の挿入関数が用意されています。
// C++
void operator<<=(Any&, const T&); // copying form
void operator<<=(Any&, T*); // non-copying form
コピー形式は、呼出し側に関して見れば、最初に示した形式とほぼ同じです。
前述の「左シフト代入」演算子は、次のように型付き値をanyに挿入するために使用します。
// C++
Long value = 42;
Any a;
a <<= value;
この場合、型Longにオーバーロードされたoperator<<=のバージョンは、Any変数の値とTypeCodeの両方を適切に設定します。
operator<<=を使用してanyの値を設定することは、次のことを意味します。
operator<<=のコピー・バージョンの場合、Anyの値の存続期間は、operator<<=に渡された値の存続期間に依存しません。Anyの実装では、operator<<=に渡された値への参照またはポインタとして、その値を格納しません。
operator<<=の非コピー・バージョンの場合、挿入されたT*はAnyが処理します。挿入後はAnyがT*の所有権を想定するため、呼出し側は指されたデータにT*を使用してアクセスできず、Anyは指されたデータを直ちにコピーして元のデータを破棄します。
operator<<=のコピーと非コピーの両バージョンでは、Anyが保持していた前の値がすべて適切に割当て解除されます。たとえば、「型付けされていない値の処理」で説明したAny(TypeCode_ptr,void*,TRUE)コンストラクタを呼び出してAnyを作成した場合、Anyvoid*が指すメモリーの割当てを解除してから、新しい値をコピーします。
文字列型の挿入をコピーすると、次の関数が呼び出されます。
// C++
void operator<<=(Any&, const char*);
文字列型はすべてchar*にマッピングされるので、この挿入関数は、挿入された値が無制限文字列であることを想定します。制限付き文字列を正しくAnyに挿入する方法については、「Boolean、Octet、Char、および制限付き文字列の識別」を参照してください。制限付き文字列と無制限文字列の挿入をコピーせずに実行するには、Any::from_stringヘルパー型を使用します。このヘルパー型については、「Boolean、Octet、Char、および制限付き文字列の識別」を参照してください。
型保障で配列を挿入するには、「配列」で説明しているArray_forany型を使用します。ORBでは、Array_forany型ごとに、オーバーロードされたoperator<<=のバージョンが用意されています。例:
// IDL
typedef long LongArray[4][5];
// C++
typedef Long LongArray[4][5];
typedef Long LongArray_slice[5];
class LongArray_forany { ... };

void operator<<=(Any &, const LongArray_forany &);
Array_forany型は、constへの参照によって常にoperator<<=に渡されます。 Array_foranyコンストラクタのnocopyフラグは、挿入された値をコピーするか(nocopy == FALSE)、処理するか(nocopy == TRUE)を制御するために使用します。nocopyフラグはデフォルトでFALSEに指定されているため、デフォルトでは挿入がコピーされます。
Tの配列とT*には型にあいまいさがあるため、移植性のあるコードの場合は、配列をAnyに挿入するときに適切なArray_forany型を明示的に使用することをお薦めします。例:
// IDL
struct S {... };
typedef S SA[5];
// C++
struct S { ... };
typedef S SA[5];
typedef S SA_slice;
class SA_forany { ... };

SA s;
// ...initialize s...
Any a;
a <<= s; // line 1
a <<= SA_forany(s); // line 2
行1の場合、配列型SAがその最初の要素へのポインタに集束されるため、コピーSA_forany挿入演算子ではなく、非コピーoperator<<=(Any&, S*)が呼び出されます。行2の場合、SA_forany型が明示的に作成されるので、目的の挿入演算子が呼び出されます。
オブジェクト参照のoperator<<=の非コピー・バージョンでは、次のようにT_ptr型のアドレスを取得します。
// IDL
interface T { ... };
// C++
void operator<<=(Any&, T_ptr); // copying
void operator<<=(Any&, T_ptr*); // non-copying
非コピーのオブジェクト参照の挿入では、T_ptr*が指すオブジェクト参照を処理します。したがって、Anyが元のオブジェクト参照を複製してすぐに解放するため、挿入後に呼出し側は、T_ptrが参照するオブジェクトにアクセスできません。呼出し側は、T_ptr自体のストレージの所有権を保持します。
operator<<=のコピー・バージョンは、Any_var型でもサポートされます。
Anyからの抽出
型保障の方法でanyから値を取得できるようにするために、ORBではOMG IDLの型Tごとに次の演算子が用意されています。
// C++
Boolean operator>>=(const Any&, T&);
この関数シグネチャでは、通常は値で渡されるプリミティブ型があれば十分です。型Tの値が大きすぎて完全に値を渡すことができない場合、ORBでは次のように別のシグネチャが提供されます。
// C++
Boolean operator>>=(const Any&, T*&);
この関数の最初の形式は、次の型にのみ使用されます。
その他の型については、すべて関数の2番目の形式が使用されます。
前述の「右シフト代入」演算子は、次のように型付き値をanyから抽出するために使用します。
// C++
Long value;
Any a;
a <<= Long(42);
if (a >>= value) {
// ... use the value ...
}
この場合、型Longoperator>>=のバージョンは、Anyが型Longの値を格納しているかどうかを判別します。格納している場合、呼出し側によって提供された参照変数にその値をコピーし、TRUEを返します。Anyが型Longの値を格納していない場合、呼出し側のリファレンス変数の値は変更されず、operator>>=FALSEを返します。
型が非プリミティブの場合、ポインタが抽出を行います。次に、OMG IDL構造体の例を示します。
// IDL
struct MyStruct {
long lmem;
short smem;
};
上記の構造体は、次のようにAnyから抽出できます。
// C++
Any a;
// ... a is somehow given a value of type MyStruct ...
MyStruct *struct_ptr;
if (a >>= struct_ptr) {
// ... use the value ...
}
抽出に成功した場合、呼出し側のポインタはAnyが管理するストレージを指し、operator>>=TRUEを返します。呼出し側は、このストレージのdeleteまたは解放を試行する必要はありません。また、代入、挿入、またはreplace関数によってAny変数が置き換えられた後、またはAny変数が破棄された後に、呼出し側はストレージを使用する必要もありません。ただし、これらの抽出演算子でT_var型を使用しないよう注意する必要があります。これは、Anyによって所有されるストレージを抽出演算子が削除しようとするためです。
抽出に失敗した場合、呼出し側のポインタの値はNULLポインタと同じに設定され、operator>>=FALSEを返します。
配列型を正しく抽出するには、Array_forany型を使用します。この型については、「配列」を参照してください。
次に、OMG IDLの例を示します。
// IDL
typedef long A[20];
typedef A B[30][40][50];
// C++
typedef Long A[20];
typedef Long A_slice;
class A_forany { ... };
typedef A B[30][40][50];
typedef A B_slice[40][50];
class B_forany { ... };

Boolean operator>>=(const Any&, A_forany&); // for type A
Boolean operator>>=(const Any&, B_forany&); // for type B
Array_forany型は、参照によって常にoperator>>=に渡されます。
文字列および配列の場合、アプリケーションはAnyのTypeCodeをチェックします。これは、抽出値を使用する際に、アプリケーションが確実に配列オブジェクトまたは文字列オブジェクトのバウンドを超えないようにするためです。
operator>>=は、Any_var型でもサポートされます。
Boolean、Octet、Char、および制限付き文字列の識別
OMG IDLの型のBoolean、octet、およびcharは、特定のC++型にマッピングする必要はありません。そのため、型保障Anyインタフェースで使用できるようにするために、これらの型を互いに識別する方法が別に必要となります。同じく、制限付き文字列と無制限文字列の両方がchar*にマッピングされるため、これらを識別する別の方法を提供する必要があります。ここでは、識別を行うために、Anyクラス・インタフェース内でネストされた新しいヘルパー型をいくつか導入します。ヘルパー型を使用した識別の例を次に示します。
// C++
class Any
{
public:
// special helper types needed for boolean, octet,
// char, and bounded string insertion
struct from_boolean {
from_boolean(Boolean b) : val(b) {}
Boolean val;
};
struct from_octet {
from_octet(Octet o) : val(o) {}
Octet val;
};
struct from_char {
from_char(Char c) : val(c) {}
Char val;
};
struct from_string {
from_string(char* s, ULong b,
Boolean nocopy = FALSE) :
val(s), bound(b) {}
char *val;
ULong bound;
};
void operator<<=(from_boolean);
void operator<<=(from_char);
void operator<<=(from_octet);
void operator<<=(from_string);
// special helper types needed for boolean, octet,
// char, and bounded string extraction
struct to_boolean {
to_boolean(Boolean &b) : ref(b) {}
Boolean &ref;
};
struct to_char {
to_char(Char &c) : ref(c) {}
Char &ref;
};
struct to_octet {
to_octet(Octet &o) : ref(o) {}
Octet &ref;
};
struct to_string {
to_string(char *&s, ULong b) : val(s), bound(b) {}
char *&val;
ULong bound;
};
Boolean operator>>=(to_boolean) const;
Boolean operator>>=(to_char) const;
Boolean operator>>=(to_octet) const;
Boolean operator>>=(to_string) const;
// other public Any details omitted
private:
// these functions are private and not implemented
// hiding these causes compile-time errors for
// unsigned char
void operator<<=(unsigned char);
Boolean operator>>=(unsigned char &) const;
};
ORBでは、これらの特別なヘルパー型用に、オーバーロードのoperator<<=およびoperator>>=関数を提供します。これらのヘルパー型は、次のように使用します。
// C++
Boolean b = TRUE;
Any any;
any <<= Any::from_boolean(b);
// ...
if (any >>= Any::to_boolean(b)) {
// ...any contained a Boolean...
}

char* p = "bounded";
any <<= Any::from_string(p, 8);
// ...
if (any >>= Any::to_string(p, 8)) {
// ...any contained a string<8>...
}
制限値が0(ゼロ)の場合、無制限文字列を示します。
Anyへの制限付き文字列または無制限文字列の挿入をコピーせずに行う場合、from_stringコンストラクタでnocopyフラグをTRUEに設定する必要があります。
// C++
char* p = string_alloc(8);
// ...initialize string p...
any <<= Any::from_string(p, 8, 1); // any consumes p
boolean、charおよびoctetがすべてC++型のunsigned charにマッピングされる場合、boolean、charまたはoctet型のanyの直接挿入または抽出を試行すると、unsigned char用のプライベートで未実装のoperator<<=およびoperator>>=関数によって、コンパイル・エラーが発生します。
// C++
Octet oct = 040;
Any any;
any <<= oct; // this line will not compile
any <<= Any::from_octet(oct); // but this one will
Objectへの型の拡大
Anyからオブジェクト参照を基本Object型として抽出する方が望ましい場合があります。これを実行するには、boolean、char、およびoctetの抽出に必要なヘルパー型と同様のヘルパー型を使用します。
// C++
class Any
{
public:
...
struct to_object {
to_object(Object_ptr &obj) : ref(obj) {}
Object_ptr &ref;
;
Boolean operator>>=(to_object) const;
...
};
to_objectヘルパー型は、Anyからオブジェクト参照を基本Object型として抽出するために使用します。AnyにそのTypeCodeとして示されたオブジェクト参照型の値がある場合、抽出関数operator>>=(to_object)は、その格納されているオブジェクト参照を明示的にObject型に拡大し、TRUEを返します。それ以外の場合は、FALSEを返します。抽出されたオブジェクト参照の型の拡大を実行するのは、オブジェクト参照抽出関数のみです。通常のオブジェクト参照の抽出と同じく、to_object抽出演算子は、オブジェクト参照を複製しません。
型付けされていない値の処理
状況によっては、Anyへの型保障のインタフェースでは十分でない場合があります。たとえば、データ型をバイナリ形式でファイルから読み込んで、Any型の値を作成するために使用する場合です。このような場合、Anyクラスは明示的なTypeCodeおよび汎用のポインタにコンストラクタを提供します。
// C++
Any(TypeCode_ptr tc, void *value, Boolean release = FALSE);
コンストラクタは、指定されたTypeCode擬似オブジェクト参照を複製します。releaseパラメータがTRUEの場合、Anyオブジェクトはvalueパラメータが指すストレージの所有権を想定します。valueパラメータがrelease=TRUEの指定でAnyに対して処理された後は、呼出し側はこのパラメータの存続期間を想定できません。これは、Anyがvalueパラメータをコピーして、直ちに元のポインタを解放するためです。releaseパラメータがデフォルトのFALSEの場合、Anyオブジェクトは、valueによって指されるメモリーを呼出し側が管理すると想定します。valueパラメータはNULLポインタでもかまいません。
Anyクラスでは、3つの危険な操作も定義します。
// C++
void replace(
TypeCode_ptr,
void *value,
Boolean release = FALSE
);
TypeCode_ptr type() const;
const void *value() const;
replace関数は、型保障挿入インタフェースで使用不可能な型で使用します。したがって、この関数は前述のコンストラクタに似ています。既存のTypeCodeは解放され、必要に応じて値のストレージの割当てが解除されます。TypeCode関数のパラメータは複製されます。releaseパラメータがTRUEの場合、Anyオブジェクトは、valueパラメータが指すストレージの所有権を想定します。valueパラメータがrelease=TRUEの指定でAny::replace関数に対して処理された後は、Anyはこのパラメータの存続期間を想定できません。これは、Anyがvalueパラメータをコピーして、直ちに元のポインタを解放するためです。releaseパラメータがデフォルトのFALSEの場合、Anyオブジェクトは、値が入っているメモリーを呼出し側が管理すると想定します。replace関数のvalueパラメータはNULLポインタでもかまいません。
前述のコンストラクタもreplace関数も型保障ではありません。特に、TypeCodeとvoid*引数の実際の型との一貫性については、実行時にコンパイラは保証しません。一致しないTypeCodeと値でAnyが作成される場合の、ORB実装の動作は定義されません。
type関数は、Anyに関連付けられたTypeCodeにTypeCode_ptr擬似オブジェクト参照を返します。すべてのオブジェクト参照の戻り値と同様に、リファレンスが不要になったときに呼出し側は、それを解放するか、または自動管理を行うためにTypeCode_var変数を割り当てる必要があります。
value関数は、Anyに格納されているデータへのポインタを返します。Anyに関連付けられている値がない場合、value関数はNULLポインタを返します。
Anyのコンストラクタ、デストラクタ、代入演算子
デフォルトのコンストラクタは、値を作成せずに、型tk_nullのTypeCodeでAnyを作成します。コピー・コンストラクタは、AnyパラメータのTypeCode_ptr_duplicateを呼び出し、パラメータの値をディープ・コピーします。代入演算子は、それ自身のTypeCode_ptrを解放し、必要に応じて現在の値のストレージを割当て解除します。その後、AnyパラメータのTypeCode_ptrを複製し、パラメータの値をディープ・コピーします。デストラクタは、TypeCode_ptrreleaseを呼び出し、必要に応じて値のストレージを割当て解除します。
その他のコンストラクタについては、「型付けされていない値の処理」という項を参照してください。
Anyクラス
Anyクラスの定義の詳細は、「Anyクラスのメンバー関数」という項を参照してください。
値型
この項は、Object Management Group (OMG)の『Common Object Request Broker: Architecture and Specification, Revision 2.4.2』(2001年2月)の第3章、第5章、および第6章、および『CORBA C++ Language Mapping Specification』(1999年6月)に記載されている情報に基づいています。OMGの許可を得て使用されています。
概要
オブジェクト(具体的にはオブジェクトがサポートするインタフェース型)は、IDLインタフェースに定義され、そのため任意に実装できます。実装にほとんど制約がない分散オブジェクト・システムを導入することには大きな価値があります。ただし、オブジェクトを参照ではなく値で渡すことができる方が望ましい場合がよくあります。これは特に、オブジェクトの主な目的がデータをカプセル化することである場合や、アプリケーションで明示的にオブジェクトのコピーを作成する必要がある場合に有用です。
オブジェクトを値で渡すセマンティクスは、標準のプログラミング言語のものに似ています。値で渡されるパラメータの受信側は、オブジェクトの状態に関する説明を受け取ります。次に、その状態で新しいインスタンスをインスタンス化しますが、アイデンティティは送信側とは別のものになります。パラメータ渡しの操作が完了すると、2つのインスタンス間に関係は存在しないものとみなされます。
受信側はインスタンスをインスタンス化する必要があるため、オブジェクトの状態と実装に関する情報を認識している必要があります。このため、次のように、値型ではCORBA構造体とCORBAインタフェースの間をブリッジするセマンティクスを提供します。
アーキテクチャ
値型の基本的な概念は比較的簡単です。値型は、ある意味、通常のIDLインタフェース型と構造体の中間のようなものです。値型を使用するというのは、インタフェース型以外に追加でいくつかのプロパティ(状態)と実装詳細を指定したことを知らせるアプリケーション・プログラマからの合図です。この情報を指定すると、インタフェース型の制約以外に実装の選択に関して追加でいくつか制約が課されます。これは、ここで指定したセマンティクスと言語マッピングの両方に反映されます。
利点
値型(値で渡すことが可能なオブジェクト)をサポートする前は、すべてのCORBAオブジェクトにオブジェクト参照がありました。特定のオブジェクトで複数のクライアントを呼び出すと、いずれのクライアントでも同じオブジェクト参照が使用されます。オブジェクトのインスタンスはサーバーORBに残り、その状態はクライアントORBではなくサーバーORBによって維持されました。
値型は、CORBAアーキテクチャに重要な追加が行われたことを表します。参照で渡されるオブジェクトの場合と同じく、値型にも状態およびメソッドがあります。ただし、オブジェクト参照はなく、常にプログラミング言語オブジェクトとしてローカルに呼び出されます。受信側からのリクエストに応じて、値型は自身の状態を送信コンテキストにパッケージング化し、伝送路経由で受信側に自身の状態を送信します。受信側では、インスタンスが作成されて、送信された状態が移入されます。送信側では、クライアント側のインスタンスをそれ以上制御できません。このため、受信側ではそのインスタンスを後でローカルに呼び出すことができます。このモデルにより、ネットワークで通信するときに伴う遅延が発生しなくなります。このような遅延は、大規模ネットワークでは重要になる場合があります。値型を追加すると、CORBA実装を大規模なデータ処理要件にあわせて拡張するのがさらに容易になります。
このため、値型に欠かせない特性は、その実装が常にローカルであるということです。つまり、具体的なプログラミング言語で値型を明示的に使用すると、常にローカルな実装を使用することが保証され、リモート呼出しが必要なくなります。値型にはアイデンティティがなく(自身の値が自身のアイデンティティ)、ORBに登録されません。
値型の例
次に、IDLの値型の例を示します。これは、Object Management Group (OMG)の「CORBA C++ Language Mapping Specification」(1999年6月)から引用したものです。
// IDL
valuetype Example {
short op1();
long op2(in Example x);
private short val1;
public long val2;
private string val3;
private float val4;
private Example val5;
};
この値型のC++マッピングは次のとおりです。
// C++
class Example : public virtual ValueBase {
public:
virtual Short op1() = 0;
virtual Long op2(Example*) = 0;
virtual Long val2() const = 0;
virtual void val2(Long) = 0;
static Example* _downcast(ValueBase*);
protected:
Example();
virtual ~Example();
virtual Short val1() const = 0;
virtual void val1(Short) = 0;
virtual const char* val3() const = 0;
virtual void val3(char*) = 0;
virtual void val3(const char*) = 0;
virtual void val3(const String_var&) = 0;
virtual Float val4() const = 0;
virtual void val4(Float) = 0;
virtual Example* val5() const = 0;
virtual void val5(Example*) = 0;
private:
// private and unimplemented
void operator=(const Example&);
};
class OBV_Example : public virtual Example {
public:
virtual Long val2() const;
virtual void val2(Long);
protected:
OBV_Example();
OBV_Example(Short init_val1, Long init_val2,
const char* init_val3, Float init_val4,
Example* init_val5);
virtual ~OBV_Example();
virtual Short val1() const;
virtual void val1(Short);
virtual const char* val3() const;
virtual void val3(char*);
virtual void val3(const char*);
virtual void val3(const String_var&);
virtual Float val4() const;
virtual void val4(Float);
virtual Example* val5() const;
virtual void val5(Example*);
// ...
};
固定長ユーザー定義型と可変長ユーザー定義型
ユーザー定義型のメモリー管理規則およびメンバー関数のシグネチャは、その型が固定長か可変長かどうかによって異なります。ユーザー定義型は、次のいずれかである場合には可変長です。
上記の一覧に型が該当しない場合、その型は固定長です。
varクラスの使い方
メモリー管理を簡素化するために、自動変数(var)が用意されています。varはvarクラスを通じて提供されます。このクラスは、型に必要なメモリーの所有権を想定し、varオブジェクトのインスタンスが破棄されたり、新しい値がvarオブジェクトに割り当てられたときにメモリーを解放します。
Oracle Tuxedoでは、次の型のvarクラスが用意されています。
String (CORBA::String_var)
Object references (CORBA::Object_var)
ユーザー定義のOMG IDLの型(structunionsequencearray、およびinterface)
varクラスには共通のメンバー関数がありますが、OMG IDLの型によってはさらに追加で演算子をサポートできます。OMG IDLの型TYPEの場合、TYPE_varクラスは、コンストラクタ、デストラクタ、代入演算子、および基底のTYPE型にアクセスするための演算子を格納しています。次に、varクラスの例を示します。
class TYPE_var
{
public:
// constructors
TYPE_var();
TYPE_var(TYPE *);
TYPE_var(const TYPE_var &);
// destructor
~TYPE_var();

// assignment operators
TYPE_var &operator=(TYPE *);
TYPE_var &operator=(const TYPE_var &);

// accessor operators
TYPE *operator->();
TYPE *operator->() const;
TYPE_var_ptr in() const;
TYPE_var_ptr& inout();
TYPE_var_ptr& out();
TYPE_var_ptr _retn();
operator const TYPE_ptr&() const;
operator TYPE_ptr&();
operator TYPE_ptr;
};
次に、各メンバー関数の詳細について説明します。
TYPE_var()
TYPE_varクラスのデフォルトのコンストラクタです。このコンストラクタは0(ゼロ)に初期化します。この値は、varクラスがTYPE *を所有することを示します。有効なTYPE *を割り当てていないかぎり、TYPE_varクラスでoperator->を呼び出すことはできません。
TYPE_var(TYPE * Value);
このコンストラクタは、指定のTYPE *パラメータの所有権を想定します。TYPE_varが破棄されると、TYPEは解放されます。Value引数は、このvarクラスが所有するTYPEへのポインタです。このポインタは0(ゼロ)に指定しないでください。
TYPE_var(const TYPE_var & From);
このコピー・コンストラクタは、新しいTYPEを割り当てて、Fromパラメータが所有するTYPEに格納されているデータをディープ・コピーします。TYPE_varが破棄されると、TYPEのコピーは解放または削除されます。Fromパラメータには、コピー元のTYPEを指すvarクラスを指定します。
~TYPE_var();
このデストラクタは、varクラスが所有するTYPEを適切なメカニズムで解放します。文字列の場合は、CORBA::string_freeルーチンです。その他の参照の場合は、 CORBA::release ルーチンです。その他の型の場合はdelete、または割当て済メモリーを解放するために生成された静的ルーチンです。
TYPE_var &operator=(TYPE * NewValue);
この代入演算子は、NewValueパラメータが指すTYPEの所有権を想定します。現在、TYPE_varTYPEを所有している場合、それを解放してから、NewValueパラメータの所有権を想定します。NewValue引数は、このvarクラスが所有するTYPEへのポインタです。このポインタは0(ゼロ)に指定しないでください。
TYPE_var &operator=(const TYPE_var &From);
この代入演算子は、新しいTYPEを割り当てて、From TYPE_varパラメータが所有するTYPEに格納されているデータをディープ・コピーします。現在、TYPE_varTYPEを所有している場合は解放されます。TYPE_varが破棄されると、TYPEのコピーは解放されます。Fromパラメータには、コピー元のデータを指すvarクラスを指定します。
TYPE *operator->();
TYPE *operator->() const;
これらの演算子は、varクラスが所有しているTYPEへのポインタを返します。varクラスは、引き続きTYPEを所有し、TYPEを解放します。varが有効なTYPEを所有していない場合は、operator->を使用できません。TYPE_varが破棄された後に、この戻り値の解放またはアクセスを試行しないでください。
TYPE_var_ptr in() const;
TYPE_var_ptr& inout();
TYPE_var_ptr& out();
TYPE_var_ptr _retn();
暗黙的な変換を実行すると、一部のC++コンパイラやコードの可読性に問題が生じることがあります。そのため、TYPE_var型では、パラメータ渡しのために明示的な変換を実行できるようにするメンバー関数もサポートしています。TYPE__varおよびinパラメータを渡すには、in()メンバー関数を、inoutパラメータを渡す場合はinout()メンバー関数を、outパラメータを渡す場合はout()メンバー関数をそれぞれ呼び出します。TYPE__varから戻り値を取得するには、_return()関数を呼び出します。各TYPE_var型について、これらの関数の戻り値の型はそれぞれ、表13-7で示すininoutout、および基底の型TYPEの戻り値モードの型にそれぞれ一致します。
ユーザー定義のデータ型用にサポートされている演算子には、いくつかの違いがあります。表13-3では、生成されたC++コードにおける各OMG IDLのデータ型でサポートされる様々な演算子について説明しています。表13-3で示すように、代入演算子はすべてのデータ型でサポートされるので、比較には含まれていません。
 
 
表13-4では、シグネチャを示します。
 
TYPE * operator-> ()
TYPE * operator-> () const
TYPE * operator-> ()
TYPE * operator-> () const
TYPE * operator-> ()
TYPE * operator-> () const
TYPE & operator[](CORBA::Long index)
TYPE_slice & operator[](CORBA::Long index) TYPE_slice & operator[](CORBA::Long index) const
 
シーケンスvar
シーケンスvarでは、次のoperator[]メンバー関数を追加でサポートします。
TYPE &operator[](CORBA::ULong Index);
この演算子は、varクラスが所有するシーケンスのoperator[]を呼び出します。operator[]は、指定の索引でシーケンスの適切な要素へのリファレンスを返します。Index引数には、戻り値となる要素の索引を指定します。この索引は、現在のシーケンスの長さを超えることはできません。
配列var
配列varでは、配列要素にアクセスするためにoperator->ではなく、次のoperator[]メンバー関数を追加でサポートします。
TYPE_slice& operator[](CORBA::ULong Index);
const TYPE_slice & operator[](CORBA::ULong Index) const;
これらの演算子は、指定された索引で配列スライスへの参照を返します。配列のスライスとは、元の配列の最初のサイズを除いたすべてのサイズを持つ配列のことです。配列で生成されるクラスのメンバー関数は、スライスへのポインタを使用して、配列へのポインタを返します。Index引数には、戻り値となるスライスの索引を指定します。この索引は、配列のサイズを超えることはできません。
文字列var
この項と「シーケンスvar」という項で説明するメンバー関数の文字列varには、char *TYPEがあります。文字列varでは、次のメンバー関数を追加でサポートします。
String_var(char * str)
このコンストラクタは、文字列からString_varを作成します。str引数には、想定される文字列を指定します。strポインタを使用して、データにアクセスしないでください。
String_var(const char * str)
String_var(const String_var & var)
このコンストラクタは、const文字列からString_varを作成します。str引数には、コピー元となるconst文字列を指定します。var引数には、コピー元となる文字列へのリファレンスを指定します。
String_var & operator=(char * str)
この代入演算子は、CORBA::string_freeを使用して格納されている文字列を解放してから、入力文字列の所有権を想定します。str引数には、このString_varオブジェクトが所有権を想定する文字列を指定します。
String_var & operator=(const char * str)
String_var & operator=(const String_var & var)
この代入演算子は、CORBA::string_freeを使用して格納されている文字列を解放してから、入力文字列をコピーします。Data引数には、このString_varオブジェクトが所有権を想定する文字列を指定します。
char operator[] (Ulong Index)
char operator[] (Ulong Index) const
これらの配列演算子は、文字列内の文字へのアクセスを提供する上付きの演算子です。Index引数には、配列内の特定の文字にアクセスするときに使用する配列の索引を指定します。索引の基数はゼロです。Char operator[] (Ulong Index)関数の戻り値は、lvalueとして使用できます。
Char operator[] (Ulong Index) const関数の戻り値は、lvalueとして使用できません。
outクラス
構造化された型(構造体、ユニオン、シーケンス)、配列およびインタフェースには、対応する_outクラスが生成されます。outクラスは、可変長型および固定長型へのポインタのメモリー管理を簡素化するために用意されています。outクラスと共通のメンバー関数の詳細は、「outクラスの使い方」という項を参照してください。
ユーザー定義のデータ型用にサポートされている演算子には、いくつかの違いがあります。表13-5では、生成されたC++コードにおける各OMG IDLのデータ型でサポートされる様々な演算子について説明しています。表13-5で示すように、代入演算子はすべてのデータ型でサポートされるので、比較には含まれていません。
 
表13-6では、シグネチャを示します。
 
TYPE * operator-> ()
TYPE * operator-> () const
TYPE * operator-> ()
TYPE * operator-> () const
TYPE * operator-> ()
TYPE * operator-> () const
TYPE & operator[](CORBA::Long index)
TYPE_slice & operator[](CORBA::Long index) TYPE_slice & operator[](CORBA::Long index) const
outクラスの使い方
TYPE_varoutパラメータとして渡すと、参照先であった前の値はすべて暗黙的に削除する必要があります。の要件を満たす上で十分なフックをORBに付与するために、各T_var型には対応するTYPE_out型があります。この型は、outパラメータ型としてのみ使用します。
注意:
プログラマは、_outクラスを直接インスタンス化できません。そのため、_outクラスは関数のシグネチャでのみ指定してください。
可変長型のTYPE_out型の全般的な形式は、次のとおりです。
// C++
class TYPE_out
{
public:
TYPE_out(TYPE*& p) : ptr_(p) { ptr_ = 0; }
TYPE_out(TYPE_var& p) : ptr_(p.ptr_) { delete ptr_; ptr_ = 0;}
TYPE_out(TYPE_out& p) : ptr_(p.ptr_) {}
TYPE_out& operator=(TYPE_out& p) { ptr_ = p.ptr_;
return *this;
}
Type_out& operator=(Type* p) { ptr_ = p; return *this; }

operator Type*&() { return ptr_; }
Type*& ptr() { return ptr_; }

Type* operator->() { return ptr_; }

private:
Type*& ptr_;
// assignment from TYPE_var not allowed
void operator=(const TYPE_var&):
};
最初のコンストラクタは、参照データ・メンバーをT*&引数にバインドし、ポインタをゼロ(0)ポインタ値に設定します。2番目のコンストラクタは、リファレンス・データ・メンバーをTYPE_var引数が保持するポインタにバインドし、ポインタに対してdeleteを呼び出します(その際、型がString_outの場合はstring_free()を、配列型TYPETYPE_varの場合はTYPE_free()を呼び出します)。3番目のコンストラクタはコピー・コンストラクタで、コンストラクタ引数のデータ・メンバーによって参照される同じポインタにリファレンス・データ・メンバーをバインドします。
他のTYPE_outから代入すると、TYPE_out引数によって参照されるTYPE*がデータ・メンバーにコピーされます。TYPE*のオーバーロードの代入演算子は、ポインタ引数をデータ・メンバーに代入するだけです。この意味で、TYPE_out型の動作は、TYPE*とまったく同じです。TYPE*&変換演算子は、データ・メンバーを返します。ptr()メンバー関数もデータ・メンバーを返しますが、暗黙的な変換の実行を避ける場合に使用できます。オーバーロードの矢印演算子(operator->())を使用すると、TYPE*データ・メンバーが指すデータ構造体のメンバーにアクセスできます。準拠アプリケーションでは、有効な非NULL TYPE*TYPE_outが初期化済ない限り、オーバーロードのoperator->()を呼び出すことはできません。
対応する_var型のインスタンスから、TYPE_outに代入することはできません。これは、アプリケーション開発者がコピーを行うかどうか、またはTYPE_varTYPE_outに代入できるよう、それが管理するポインタの所有権を返すかどうかを判定する方法がないためです。TYPE_varTYPE_outにコピーするには、アプリケーションで次のようにnewを使用する必要があります。
// C++
TYPE_var t = ...;
my_out = new
TYPE(t.in()); // heap-allocate a copy
通常、tに対して呼び出されるin()関数は、const TYPE&を戻して、新しく割り当てられたTインスタンスのコピー・コンストラクタを呼び出すことができるようにします。
また、TYPE_varで、T_outパラメータで返されるよう、それが管理するポインタの所有権を返すには、アプリケーションで、次のようにTYPE_var::_retn()関数を使用する必要があります。
// C++
TYPE_var t = ...;
my_out = t._retn(); // t yields ownership, no copy
TYPE_out型は、アプリケーションで作成または破棄される汎用目的のデータ型としては機能しません。この型は必要なメモリー管理を適切に行う目的で、操作のシグネチャの内部でのみ使用する型です。
オブジェクト参照のoutパラメータ
__varoutパラメータとして渡すと、参照先の前の値はすべて暗黙的に解放する必要があります。この要件を満たす上でC++マッピング実装に十分なフックを付与するために、オブジェクト参照型ごとに_out型が生成されます。この型は、outパラメータ型としてのみ使用します。たとえば、インタフェースTYPEの場合、オブジェクト参照型TYPE_ptr、ヘルパー型TYPE_var、およびoutパラメータ型TYPE_outが生成されます。オブジェクト参照_out型の全般的な形式は次のとおりです。
// C++
class
TYPE_out
{
public:
TYPE_out(TYPE_ptr& p) : ptr_(p) { ptr_ = TYPE::_nil(); }
TYPE_out(TYPE_var& p) : ptr_(p.ptr_) {
release(ptr_); ptr_ =
TYPE::_nil();
}
TYPE_out(TYPE_out& a) : ptr_(a.ptr_) {}
TYPE_out& operator=(TYPE_out& a) {
ptr_ = a.ptr_; return *this;
}
TYPE_out& operator=(const TYPE_var& a) {
ptr_ =
TYPE::_duplicate(TYPE_ptr(a)); return *this;
}
TYPE_out& operator=(TYPE_ptr p) { ptr_ = p; return *this; }
operator
TYPE_ptr&() { return ptr_; }
TYPE_ptr& ptr() { return ptr_; }
TYPE_ptr operator->() { return ptr_; }

private:
TYPE_ptr& ptr_;
};
シーケンスout
シーケンスoutでは、次のoperator[]メンバー関数を追加でサポートします。
TYPE &operator[](CORBA::ULong Index);
この演算子は、outクラスが所有するシーケンスのoperator[]を呼び出します。operator[]は、指定の索引でシーケンスの適切な要素へのリファレンスを返します。Index引数には、戻り値となる要素の索引を指定します。この索引は、現在のシーケンスの長さを超えることはできません。
配列out
配列outでは、配列要素にアクセスするためにoperator->ではなく、次のoperator[]メンバー関数を追加でサポートします。
TYPE_slice& operator[](CORBA::ULong Index);
const TYPE_slice & operator[](CORBA::ULong Index) const;
これらの演算子は、指定された索引で配列スライスへの参照を返します。配列のスライスとは、元の配列の最初のサイズを除いたすべてのサイズを持つ配列のことです。配列で生成されるクラスのメンバー関数は、スライスへのポインタを使用して、配列へのポインタを返します。Index引数には、戻り値となるスライスの索引を指定します。この索引は、配列のサイズを超えることはできません。
文字列out
String_varoutパラメータとして渡すと、参照先の前の値はすべて暗黙的に解放する必要があります。この要件を満たす上でC++マッピング実装に十分なフックを付与するために、文字列型にもCORBAネームスペースでString_out型が生成されます。この型は、文字列outパラメータ型としてのみ使用します。String_out型の全般的な形式は次のとおりです。
// C++
class String_out
{
public:
String_out(char*& p) : ptr_(p) { ptr_ = 0; }
String_out(String_var& p) : ptr_(p.ptr_) {
string_free(ptr_); ptr_ = 0;
}
String_out(String_out& s) : ptr_(s.ptr_) {}
String_out& operator=(String_out& s) {
ptr_ = s.ptr_; return *this;
}
String_out& operator=(char* p) {
ptr_ = p; return *this;
}
String_out& operator=(const char* p) {
ptr_ = string_dup(p); return *this;
}
operator char*&() { return ptr_; }
char*& ptr() { return ptr_; }
private:
char*& ptr_;
// assignment from String_var disallowed
void operator=(const String_var&);
};
最初のコンストラクタは、参照データ・メンバーをchar*&引数にバインドします。2番目のコンストラクタは、リファレンス・データ・メンバーをString_var引数が保持するchar*にバインドし、文字列に対してstring_free()を呼び出します。3番目のコンストラクタはコピー・コンストラクタで、その引数のデータ・メンバーにバインドされる同じchar*に、リファレンス・データ・メンバーをバインドします。
他のString_outから代入すると、String_out引数によって参照されるchar*が、データ・メンバーによって参照されるchar*にコピーされます。char*のオーバーロードの代入演算子は、char*引数をデータ・メンバーに代入するだけです。const char*のオーバーロードの代入演算子は、引数を複製して結果をデータ・メンバーに代入します。代入を行っても、以前に保持されていた文字列はまったく削除されません。この意味で、String_out型の動作は、char*とまったく同じです。char*&変換演算子は、データ・メンバーを返します。ptr()メンバー関数もデータ・メンバーを返しますが、暗黙的な変換の実行を避ける場合に使用できます。
String_varからString_outへの代入はできません。これは、メモリー管理にあいまいさが生じるためです。特に、String_varによって所有される文字列をString_outが取得するときに、コピーが行われるか、コピーなしで行われるかどうかを判別することは不可能です。String_varからの代入が不可能なため、アプリケーション開発者は次のように明示的に指定しなければなりません。
// C++
void
A::op(String_out arg)
{
String_var s = string_dup("some string");
...
out = s; // disallowed; either
out = string_dup(s); // 1: copy, or
out = s._retn(); // 2: adopt
}
コメントで「1」とマークされた行の場合、呼出し側はString_varが所有する文字列を明示的にコピーし、結果をout引数に代入しています。また、呼出し側は、コメントで「2」とマークされた行で示すように、String_varに文字列の所有権を強制的に放棄させるというテクニックも使用できます。これにより、メモリー管理のエラーを発生させずにout引数に文字列を返すことができます。
引数の受け渡しの考慮事項
パラメータ渡しモードのマッピングでは、効率の必要性と簡潔さの必要性のバランスが取られます。プリミティブ型、列挙およびオブジェクト参照の場合、
モードは単純で、プリミティブと列挙用の型
P、およびインタフェース型A用の型A_ptrを渡します。
集約型は複雑です。これは、いつ、どのようにパラメータのメモリーを割り当てるか、または割当て解除するかという問題があるためです。パラメータマッピングは単純です。これは、パラメータのストレージが呼出し側によって割り当てられ、読取り専用であるためです。outパラメータとinoutパラメータのマッピングは、ほかと比較して問題が多くあります。可変長型の場合、呼出し先はストレージの一部またはすべてを割り当てる必要があります。呼出し側の割当てという点では、3つの浮動小数点値のメンバーを格納する構造体として表されるPoint型など、固定長型の方がスタック割当てが可能なので好ましいと言えます。
両方の割当て方法に対応するために、分割割当てで生じる可能性のある混同を未然に排除します。また、コピーを実行するときに、マッピングで固定長の集約体T用のT&と、可変長のT用のT*&との間に混同が生じないようにする必要があります。このような手法を採る理由は、構造体が固定長か可変長かによって構造体の使用方法が異なることにあります。ただし、呼出し側が管理対象の型T_varを使用する場合でも、マッピングはT_var&で一貫しています。
outパラメータとinoutパラメータのマッピングでは、T_varが渡されるときにパラメータ内の以前の可変長データをすべて割当て解除する必要があります。これらのパラメータの初期値が操作に送信されない場合でも、Oracle Tuxedoには、outパラメータがあります。これは、パラメータに以前の呼出しの結果が格納されている可能性があるためです。T_out型が提供される目的は、T_var型からの変換時にアクセスできないストレージを解放するのに必要なフックを実装に付与することです。次に、この動作の例を示します。
// IDL
struct S { string name; float age; };
void f(out S p);
// C++
S_var s;
f(s);
// use s
f(s); // first result will be freed

S *sp; // need not initialize before passing to out
f(sp);
// use sp
delete sp; // cannot assume next call will free old value
f(sp);
outパラメータとinoutパラメータの前の値を暗黙的に割当て解除できるのは、T_var型のみです。
// IDL
void q(out string s);
// C++
char *s;
for (int i = 0; i < 10; i++)
q(s); // memory leak!
ループ内でq関数を呼び出すたびに、メモリー・リークが発生します。これは、呼出し側がout結果でstring_freeを呼び出していないことが原因です。これを修正するには、次に示す2つの方法があります。
// C++
char *s;
String_var svar;
for (int i = 0 ; i < 10; i++) {
q(s);
string_free(s); // explicit deallocation
// OR:
q(svar); // implicit deallocation
}
outパラメータに通常のchar*を使用する場合、呼出し側は変数を毎回outパラメータとして再利用する前に、明示的にメモリーを割当て解除する必要があります。一方、String_varを使用した場合は、変数をoutパラメータとして使用するたびに、割当てがすべて暗黙的に解除されます。
可変長データは、上書きする前に、明示的に解放する必要があります。たとえば、inout文字列パラメータに代入する場合、操作の実装者はまず古い文字データを削除します。同様に、inoutインタフェース・パラメータは、再割り当てされる前に解放する必要があります。パラメータのストレージを確実に解放する方法としては、次の例に示すように、ストレージをローカルT_var変数に割り当てて自動的に解放が行われるようにすることです。
// IDL
interface A;
void f(inout string s, inout A obj);
// C++
void Aimpl::f(char *&s, A_ptr &obj) {
String_var s_tmp = s;
s = /* new data */;
A_var obj_tmp = obj;
obj = /* new reference */
}
パラメータがポインタ(T*)またはポインタ(T*&)への参照として受け渡しされる場合、アプリケーションはNULLポインタを受渡しできません。これを実行すると、結果は未定義になります。特に、次のどちらかに該当する場合、呼出し側はNULLポインタを渡すことができません。
inおよびinout文字列
inおよびinout配列(最初の要素へのポインタ)
ただし、呼出し側は、outパラメータのNULL値でポインタへの参照を渡すことはできます。これは、呼出し先が値を確認せずに上書きするためです。呼出し先は、次のいずれかに該当する場合、NULLポインタを渡すことができません。
outおよび戻り値の可変長の構造体
outおよび戻り値の可変長のユニオン
outおよび戻り値の文字列
outおよび戻り値のシーケンス
outおよび戻り値の可変長または固定長の配列
outおよび戻り値のany
操作のパラメータおよびシグネチャ
表13-7には、受け渡しされる型に応じた、基本OMG IDLパラメータ渡しモードおよび戻り値の型のマッピングを示します。表13-8には、T_var型の場合の同様の情報を示します。表13-8は、あくまで参考用に提供されています。これは、T_out型がすべてのoutパラメータの実際のパラメータ型として使用される点を除けば、クライアントとサーバーの操作のシグネチャが、表13-7で示すパラメータ渡しモードでコーディングされるためです。
また、T_var型では、この型を直接渡すために必要な変換演算子をサポートします。呼出し側は、T_var型または表13-7で示すベース・タイプのインスタンスを常に渡す必要があります。呼出し先は、そのT_outパラメータが実際に表13-7の対応する、基底の型であるように扱う必要があります。
表13-7の中で、固定長の配列が適用対象となるのは、outパラメータの型が戻り値と異なる場合のみです。
これが必要となるのは、C++では関数で配列を返すことができないためです。マッピングは、配列のスライスへのポインタを返します。
配列のスライスとは、指定された元の配列の最初のサイズを除いたすべてのサイズを持つ配列のことです。
 
注意:
呼出し側は、in引数として渡される引数すべてにストレージを提供する必要があります。
 
注意:
object reference varデータ型には、擬似オブジェクト参照も含まれています。
表13-9および表13-10では、inoutパラメータとoutパラメータに関連付けられたストレージ、および戻り値の結果に対する呼出し側の作業について説明します。
 
 
呼出し側は必要なストレージをすべて割り当てます。ただし、パラメータ自体の中でカプセル化および管理できるストレージは除きます。inoutパラメータの場合、呼出し側は初期値を指定し、呼出し先はその値を変更できます。outパラメータの場合、呼出し側はストレージを割り当てますが初期化する必要はなく、呼出し先が値を設定します。関数は値で戻り値を返します。
呼出し側は、オブジェクト参照のストレージを割り当てます。inoutパラメータの場合、呼出し側は初期値を指定します。呼出し先がinoutパラメータを再割当てする場合は、まず、元の入力値でCORBA::releaseを呼び出します。inoutとして渡されたオブジェクト参照を引き続き使用するには、呼出し側は最初にリファレンスを複製する必要があります。そして、outをすべて解放してから、オブジェクト参照を返します。ほかの構造体に埋め込まれたオブジェクト参照はすべて、各構造体自体によって自動的に解放されます。
outパラメータの場合、呼出し側はポインタを割り当て、それを呼出し先に参照で渡します。呼出し先は、パラメータのの有効なインスタンスを指すようにポインタを設定します。戻り値の場合は、呼出し先は同様のポインタを返します。どちらの場合でも、呼出し先はNULLポインタを返すことはできません。
inout文字列の場合、呼出し側は、入力文字列とそれを指すchar*の両方にストレージを割り当てます。呼出し先が入力文字列の割当てを解除し、新しいストレージを指すchar*を再割り当てして出力値を保持する可能性があるため、呼出し側はstring_alloc()を使用して入力文字列を割り当てる必要があります。そのため、out文字列のサイズはin文字列のサイズに制限されません。呼出し側は、string_free()を使用してoutのストレージを削除する必要があります。呼出し先は、inoutout、または戻り値に対してNULLポインタを返すことはできません。
inoutシーケンスおよびanyの場合、シーケンスまたはanyを作成したBoolean解放パラメータの状態によっては、シーケンスまたはanyを割り当てまたは変更することにより、再割当てが行われる前に、所有しているストレージの割当てが解除される場合があります。
outパラメータの場合、呼出し側は配列スライス(元の配列の最初のサイズを除いたすべてのサイズを持つ配列)へのポインタを割り当て、参照でポインタを呼出し先に渡します。呼出し先は、配列の有効なインスタンスを指すようにポインタを設定します。
 

1
具体的には、関数名およびデータ型として使用されるexception

Copyright ©1994, 2017,Oracle and/or its affiliates. All rights reserved