![]() |
![]() |
|
|
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
string_free
注記 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};
};
次に、前の例で定義した enum への有効なリファレンスの例を示します。enum へのリファレンスは次のとおりです。
INVENT::Reply accept_reply;
accept_reply = INVENT::ACCEPT;
構造体
OMG IDL の構造体は、C++ の構造体にマッピングされます。
構造体に対して生成されたコードは、固定長か可変長かによって異なります。固定長型と可変長型の詳細については、「固定長ユーザ定義型と可変長ユーザ定義型」を参照してください。
固定長構造体と可変長構造体
可変長構造体には、代入演算子メンバ関数が別にあり、2 つの可変長構造体間の代入を処理します。
次に、OMG IDL 定義の例を示します。
// OMG IDL
module INVENT
{
// 固定長
struct Date
{
long year;
long month;
long day;
};
// 可変長
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 クラスにマッピングされます。
CORBA::String_var
CORBA::Object_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 番目の関数 (アクセサ) では、共用体の値を返しています。
共用体メンバのデータ型によっては、モディファイア関数が追加生成されます。各データ型に対して生成されるメンバ関数は次のとおりです。
basictype
で基本データ型の 2 つのメンバ関数を生成しています。void basictype (
TYPE
); // モディファイア
TYPE
basictype () const; // アクセサ
TYPE
へのマッピングについては、表 13-1 を参照してください。objtype
のオブジェクト型および Typecode 型の場合、メンバ関数は次のように生成されます。
void objtype (
TYPE
); // モディファイア
TYPE
objtype () const; // アクセサ
OMG IDL のデータ型から C++ のデータ型 TYPE
へのマッピングについては、表 13-1 を参照してください。
モディファイア・メンバ関数では、指定されたオブジェクト・リファレンス引数の所有権を想定していません。代わりに、モディファイアはオブジェクト・リファレンスまたは擬似オブジェクト・リファレンスを複製します。リファレンスが不要になったときは、リファレンスを解放してください。
enumtype
の enum
TYPE
の場合、メンバ関数は次のように生成されます。
void enumtype (
TYPE
); // モディファイア
TYPE
enumtype () const; // アクセサ
void stringInfo (char *);
// モディファイア 1
void stringInfo (const char *);// モディファイア 2
void stringInfo (const CORBA::String_var &);// モディファイア 3
const char * stringInfo () const;// アクセサ
最初のモディファイアでは、渡された char *
パラメータの所有権を想定しています。また、共用体の値に変更があったり、共用体が破棄されたときに、共用体は CORBA::string_free
メンバ関数を呼び出します。
2 番目と 3 番目のモディファイアでは、パラメータに渡されるか、または文字列 var に格納されている指定の文字列をコピーします。
アクセサ関数は、共用体の内部メモリへのポインタを返します。また、このメモリの解放を試行せず、共用体の値に変更があったり、共用体が破棄されたりした後は、このメモリにアクセスしません。
type
へのリファレンスで生成されます。
void reftype (
TYPE
&); // モディファイア
constTYPE
& reftype () const; // アクセサ
TYPE
& reftype (); // アクセサ
モディファイア関数は、入力パラメータ type
の所有権を想定していません。代わりに、関数はデータ型をコピーします。
void arraytype (
TYPE
); // モディファイア
TYPE
_slice * arraytype () const; // アクセサ
モディファイア関数は、入力パラメータ 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 Descrim);
このメンバ関数は、区別値を設定し、現在の値を解放します。Descrim
引数には、新しい区別値を指定します。引数のデータ型は、共用体の switch 文で指定した OMG IDL のデータ型で決まります。OMG IDL および C++ の各データ型については、表 13-1 を参照してください。
CORBA::Long _d () const;
この関数は現在の区別値を返します。戻り値のデータ型は、共用体の switch 文で指定した OMG IDL のデータ型で決まります。OMG IDL および C++ の各データ型については、表 13-1 を参照してください。
シーケンス
OMG IDL のシーケンスは、C++ のクラスにマッピングされます。C++ クラスには、次のものが格納されています。
各シーケンスには、次のものがあります。
要素にアクセスする場合、事前に長さを設定しておく必要があります。
次に、OMG IDL 定義の例を示します。
// OMG IDL
module INVENT
{
. . .
typedef sequence<LogItem> LogList;
}
上の定義は、次のように C++ にマッピングされます。
// C++
class LogList
{
public:
// デフォルト・コンストラクタ
LogList();
// 最大コンストラクタ
LogList(CORBA::ULong _max);
//
TYPE
* データ・コンストラクタ
LogList
(
CORBA::ULong _max,
CORBA::ULong _length,
LogItem *_value,
CORBA::Boolean _relse = CORBA_FALSE
);
// コピー・コンストラクタ
LogList(const LogList&);
// デストラクタ
~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++ クラスには、次のものが格納されています。
_narrow
関数生成されるクラスは可変長構造体と似ています。ただし、このクラスは初期化を簡単にするためのコンストラクタ、および 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
が付きます。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 の擬似オブジェクト仕様の相違点は次のとおりです。
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);
};
生成されたクライアント・アプリケーション・スタブには、スタブ・クラスに対して生成された次のコードが格納されます。
// ルーチン名: INVENT::Stub_Order::modifyOrder
//
// 関数の説明:
//
// オペレーション 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
を含める必要があります。
メンバ関数内で、「this」ポインタは、クラスで定義されたインプリメンテーション・オブジェクトのデータを参照します。データにアクセスするだけでなく、メンバ関数は同じクラスで定義されたほかのメンバ関数を暗黙的に呼び出すこともできます。次に例を示します。
// 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::A
が Mod::A
から派生します。したがって、これらのシステムでは、標準の C++ 派生ベースの変換規則によって暗黙的にサーバントをオブジェクト・リファレンスで取得できます。
// C++
MyImplOfA my_a; // A のインプリメンテーションを宣言
A_ptr a = &my_a; // C++ 派生ベースの規則で
// そのオブジェクト・リファレンスを取得
上のようなコードは、ORB 準拠のインプリメンテーションでサポートしていますが、必須ではありません。そのため、移植性はありません。移植性のある同等のコードでは、インプリメンテーション・オブジェクトで _this()
を呼び出し、未登録の場合は暗黙的にそれを登録して、そのオブジェクト・リファレンスを取得します。
// C++
MyImplOfA my_a;// A のインプリメンテーションを宣言
A_ptr a = my_a._this();// オブジェクト・リファレンスを取得
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
{
. . .
}; // Order クラス
}; // INVENT クラス
入れ子になったモジュールが複数ある場合は、複数の入れ子になったクラスが生成されます。モジュール内部にあるものはすべてモジュール・クラスの中にあり、インターフェイス内部にあるものはすべてインターフェイス・クラスの中にあります。
OMG IDL では、モジュール、インターフェイス、および型の名前を同じにすることができます。ただし、C++ 言語用のファイルを生成する場合、名前を同じにすることはできません。この制限が必要になるのは、OMG IDL の名前が同じ名前で入れ子の C++ クラスに生成される際に、これを C++ コンパイラでサポートしていないためです。
注記 現在のモジュール名と同じ名前のインターフェイスまたは型で OMG IDL から C++ コードを生成すると、BEA Tuxedo OMG IDL コンパイラでは、その情報を伝えるメッセージが出力されます。このメッセージを無視して、インターフェイスまたは型とモジュール名とを区別するために一意の名前を付けなかった場合、コンパイラによってファイルの生成時にエラーが発生したことが通知されます。
インターフェイス
OMG IDL のインターフェイスは、C++ のクラスにマッピングされます。このクラスは、OMG IDL インターフェイス内にあるオペレーション、属性、定数、およびユーザ定義の型 (UDT) を格納します。
インターフェイス INTF の場合、生成されるインターフェイス・コードには、次の項目が格納されます。
INTF
_ptr
)INTF
_var
)_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
メンバ関数を呼び出して解放する必要があります。エラーが発生した場合、ニル 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
パラメータは、このメンバ関数では変更されません。また、不要になったときは解放してください。Obj
が INTF オブジェクト・リファレンスにナロー変換できない場合は、INTF ニル・オブジェクト・リファレンスが返されます。
static
INTF
_ptr _nil ( )
この静的メンバ関数は、INTF インターフェイスの新しいニル・オブジェクト・リファレンスを返します。新しいリファレンスは、CORBA::release
メンバ関数を呼び出して解放する必要はありません。
オブジェクト・リファレンスの型
インターフェイス・クラス (INTF) は仮想クラスです。CORBA 標準では、次の処理は許可されていません。
代わりに、オブジェクト・リファレンスの型、INTF
_ ptr
クラス、または INTF
_var
クラスのいずれかを使用します。
オブジェクト・リファレンスを取得するには、_narrow
静的メンバ関数を使用します。これらのクラスでオペレーションを呼び出すには、矢印演算子 (->
) を使用します。
INTF
_var
クラスは、INTF
_var
クラスがスコープをはずれるか、または再割り当てされるときに、オブジェクト・リファレンスを自動的に解放することでメモリ管理を簡単にします。変数の型は、多くの UDT に対して生成されます。「var クラスの使い方」では、変数の型について説明しています。
属性
OMG IDL の読み取り専用の属性は、属性値を返す C++ 関数にマッピングされます。読み書き属性は、2 つのオーバーロード C++ 関数にマッピングされます。2 つの関数で 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);
};
生成されたクライアント・アプリケーション・スタブには、スタブ・クラスに対して生成された次のコードが格納されます。
// ルーチン名: INVENT::Stub_Item::itemInfo
//
// 関数の説明:
//
// 属性 INVENT::Stub_Item::itemInfo の
// クライアント・アプリケーション・スタブ・ルーチン (Interface : Item)
INVENT::itemStruct * INVENT::Stub_Item::itemInfo ( )
{
. . .
}
//
// ルーチン名: INVENT::Stub_Item::itemInfo
//
// 関数の説明:
//
// 属性 INVENT::Stub_Item::itemInfo の
// クライアント・アプリケーション・スタブ・ルーチン (Interface : Item)
void INVENT::Stub_Item::itemInfo (
const INVENT::itemStruct & itemInfo)
{
}
引数のマッピング
属性は、属性値を返すオペレーションと属性を設定するオペレーションの 2 つのオペレーションと等価です。たとえば、上記の itemInfo
属性は次と等価です。
void itemInfo (in itemStruct itemInfo);
itemStruct itemInfo ();
属性の引数のマッピングは、オペレーションの引数のマッピングと同じです。属性は、対応する C++ の型にマッピングされます。C++ の型については、表 13-1 および表 13-2 を参照してください。オペレーションでの引数のパラメータ渡しモードについては、表 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 への挿入
型セーフな方法で any
の値を設定できるようにするには、OMG IDL の型 T ごとに次のオーバーロード演算子関数が個別に用意されています。
// C++
void operator<<=(Any&, T);
この関数のシグニチャでは、次の型があれば十分です。通常、これら型は値によって渡されます。
Short
、UShort
、Long
、ULong
、Float
、Double
char*
)T_ptr
)型 T の値が大きすぎて完全に値を渡すことができない場合、次の 2 つの形式の挿入関数が用意されています。
// C++
void operator<<=(Any&, const T&); // コピー形式
void operator<<=(Any&, T*); // 非コピー形式
コピー形式は、呼び出し側に関して見れば、最初に示した形式とほぼ同じです。
上記の「左シフト代入」演算子は、次のように型付き値を 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
を作成した場合、Any
は void*
が指すメモリの割り当てを解除してから、新しい値をコピーします。文字列型の挿入をコピーすると、次の関数が呼び出されます。
// 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++
a <<= s;
struct S { ... };
typedef S SA[5];
typedef S SA_slice;
class SA_forany { ... };
SA s;
// ... s を初期化 ...
Any a;// 行 1
a <<= SA_forany(s);// 行 2
行 1 の場合、配列型 SA
がその最初の要素へのポインタに集束されるため、コピー SA_forany
挿入演算子ではなく、非コピー operator<<=(Any&, S*)
が呼び出されます。行 2 の場合、SA_forany
型が明示的に作成されるので、目的の挿入演算子が呼び出されます。
オブジェクト・リファレンスの operator<<=
の非コピー・バージョンでは、次のように T_ptr
型のアドレスを取得します。
// IDL
interface T { ... };
// C++
void operator<<=(Any&, T_ptr); // コピー
void operator<<=(Any&, T_ptr*); // 非コピー
非コピーのオブジェクト・リファレンスの挿入では、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*&);
この関数の最初の形式は、次の型にのみ使用されます。
Boolean、Char、Octet、Short、UShort、Long、ULong、Float、Double
char*
、つまり char*&
)T_ptr
)その他の型については、すべて関数の 2 番目の形式が使用されます。
上記の「右シフト代入」演算子は、次のように型付き値を any
から抽出するために使用します。
// C++
Long value;
Any a;
a <<= Long(42);
if (a >>= value) {
// ... 値を使用 ...
}
この場合、型 Long
の operator>>=
のバージョンは、Any が型 Long
の値を格納しているかどうかを判別します。格納している場合、呼び出し側によって提供されたリファレンス変数にその値をコピーし、TRUE
を返します。Any が型 Long
の値を格納していない場合、呼び出し側のリファレンス変数の値は変更されず、operator>>=
は FALSE
を返します。
型が非プリミティブの場合、ポインタが抽出を行います。次に、OMG IDL 構造体の例を示します。
// IDL
struct MyStruct {
long lmem;
short smem;
};
上記の構造体は、次のように Any から抽出できます。
// C++
Any a;
// ... a に型 MyStruct の値を指定 ...
MyStruct *struct_ptr;
if (a >>= struct_ptr) {
// ... 値を使用 ...
}
抽出に成功した場合、呼び出し側のポインタは 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&); // 型 A 用
Boolean operator>>=(const Any&, B_forany&); // 型 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:
// 特別なヘルパ型が boolean、octet、char、
// およびバウンディッド文字列の挿入に必要
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);
// 特別なヘルパ型が boolean、octet、char、
// およびバウンディッド文字列の抽出に必要
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;
// ほかのパブリック Any の詳細は省略
private:
// 下記の関数はプライベートでインプリメントされない。
// 下記の関数を隠ぺいすると、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)) {
// ... Boolean を格納した any ...
}
char* p = "bounded";
any <<= Any::from_string(p, 8);
// ...
if (any >>= Any::to_string(p, 8)) {
// ... string<8> を格納した any ...
}
バウンド値が 0 (ゼロ) の場合、アンバウンディッド文字列を示します。
Any へのバウンディッド文字列またはアンバウンディッド文字列の挿入をコピーせずに行う場合、from_string
コンストラクタで nocopy
フラグを TRUE
に設定する必要があります。
// C++
char* p = string_alloc(8);
// ... 文字列 p を初期化 ...
any <<= Any::from_string(p, 8, 1); // any は p を処理
boolean、char、および octet がすべて C++ 型の unsigned
char
にマッピングされる場合、boolean、char、または octet 型の any の直接挿入または抽出を試行すると、unsigned
char
用のプライベートでインプリメントされていない operator<<=
と operator>>=
によって、コンパイル・エラーが発生します。
// C++
Octet oct = 040;
Any any;
any <<= oct; // この行はコンパイルされない。
any<<= Any::from_octet(oct); // この行はコンパイルされる。
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_ptr
で release
を呼び出し、必要に応じて値の記憶域を割り当て解除します。
その他のコンストラクタについては、「型付けされていない値の処理」を参照してください。
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 インターフェイスで定義するので、任意のインプリメンテーションが可能になります。分散オブジェクト・システムでは、インプリメンテーション上の制約がほとんどないので、大きな値が入ります。ただし、リファレンスよりも値でオブジェクトを渡すことが可能な方が望ましい場合が多くあります。これは、オブジェクトの主要な「目的」がデータをカプセル化する場合や、アプリケーションでオブジェクトの「コピー」を明示的に作成するのが好ましい場合に、特に便利です。
値でオブジェクトを渡すセマンティクスは、標準のプログラミング言語のセマンティクスとほぼ同じです。値で渡されるパラメータの受信側は、オブジェクトの「状態」の記述を受信します。次に、受信側は新しいインタンスをその状態でインスタンス化します。その際、送信側のインスタンスの ID を個別に付けます。パラメータ渡しのオペレーションが完了すると、2 つのインスタンス間には何の関係もないものと見なされます。
受信側はインスタンスをインスタンス化する必要があるため、オブジェクトの状態とインプリメンテーションに関する情報を認識している必要があります。そこで、値型では、CORBA 構造体と CORBA インターフェイスをブリッジする、次のセマンティクスを備えています。
アーキテクチャ
値型の基本概念は比較的単純です。ある意味で値型は、「通常の」IDL インターフェイス型と構造体との中間的なものと言えます。アプリケーションのプログラマは、インターフェイス型に関係なく追加のプロパティ (状態) とインプリメンテーションの詳細が指定されることを、値型を使用して通知します。この情報の指定は、インターフェイス型に関係なくインプリメンテーション上の制約として追加されます。これは、ここで指定したセマンティクスと言語マッピングの両方に反映されます。
利点
値型 (値で渡すことが可能なオブジェクト) のサポート以前は、CORBA オブジェクトには、すべてオブジェクト・リファレンスがありました。そのため、複数のクライアントが特定のオブジェクトを呼び出すとき、クライアントは同じリファレンスを使用していました。オブジェクトのインスタンスはサーバ ORB 上に残り、その状態はクライアント ORB ではなく、サーバ ORB が管理していました。
値型は、CORBA アーキテクチャへの重要な追加機能であると言えます。リファレンスで渡されるオブジェクトと同じく、値型には状態とメソッドがありますが、オブジェクト・リファレンスはありません。また、プログラミング言語のオブジェクトと同様に常にローカルで呼び出されます。受信側から要求があると、値型は送信コンテキストでその状態をパッケージ化し、「ネットワーク経由で」状態を受信側に送信します。受信側では、インスタンスが作成され、転送された状態が設定されます。この段階以降、送信側はクライアント側のインスタンスを制御できなくなります。つまり、これ以降は、受信側がインスタンスをローカルで呼び出すことができるようになります。このモデルにより、ネットワーク経由の通信で生じる遅延を短縮することができます。この遅延は、大規模なネットワークで顕著に生じます。値型を追加することにより、CORBA インプリメンテーションの規模の調整が容易になり、大量のデータ処理要件を満たすことができます。
このように、値型の本質的な特徴は、そのインプリメンテーションが常にローカルである点です。つまり、具象的なプログラミング言語で値型を明示的に使用すると、常にローカルでインプリメンテーションが行われ、リモート呼び出しが不要になることが保証されます。値型の値自体が ID であるため、値型には ID がなく、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();
virtualExample();
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:
// プライベートおよび未インプリメント
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);
virtualOBV_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*);
// ...
};
固定長ユーザ定義型と可変長ユーザ定義型
ユーザ定義型のメモリ管理規則およびメンバ関数のシグニチャは、その型が固定長か可変長かどうかによって異なります。次のいずれか 1 つに該当する場合、ユーザ定義型は可変長です。
上記の一覧に型が該当しない場合、その型は固定長です。
var クラスの使い方
自動変数 var は、メモリ管理を簡単に行うために用意されています。var は var クラスを通じて提供されます。このクラスは、型に必要なメモリの所有権を想定し、var オブジェクトのインスタンスが破棄されたり、新しい値が var オブジェクトに割り当てられたときにメモリを解放します。
BEA Tuxedo では、次の型の var クラスが用意されています。
struct
、union
、sequence
、array
、および interface
)var クラスのメンバ関数は共通ですが、OMG IDL の型によって演算子を追加でサポートする場合があります。OMG IDL の型 TYPE
の場合、TYPE
_var クラスは、コンストラクタ、デストラクタ、代入演算子、および基となる TYPE
型にアクセスするための演算子を格納しています。次に、var クラスの例を示します。
class
TYPE
_var
{
public:
// コンストラクタ
TYPE
_var();
TYPE
_var(
TYPE
*);
TYPE
_var(const
TYPE
_var &);
~
// デストラクタ
TYPE
_var();
// 代入演算子
TYPE
_var &operator=(
TYPE
*);
TYPE
_var &operator=(const
TYPE
_var &);
// アクセサ演算子
TYPE
*operator->();
TYPE
*operator->() const;
TYPE
_var_ptr in() const;
TYPE
_var_ptr& inout();
TYPE
_var_ptr& out();
TYPE
_var_ptr _retn();
operator constTYPE
_ptr&() const;
operatorTYPE
_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
_var
が TYPE
を所有している場合、それを解放してから、NewValue
パラメータの所有権を想定します。NewValue
引数は、この var クラスが所有する TYPE
へのポインタです。このポインタは 0 (ゼロ) に指定しないでください。
TYPE
_var &operator=(const
TYPE
_var &From);
この代入演算子は、新しい TYPE
を割り当てて、From
TYPE
_var
パラメータが所有する TYPE
に格納されているデータをディープ・コピーします。現在、TYPE
_var
が TYPE
を所有している場合は解放されます。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 で示す in
、inout
、out
の型に一致し、基となる型 TYPE
のモードを返します。
ユーザ定義のデータ型によって、サポートされる演算子は一部異なります。表 13-3 では、生成された C++ コードにおける各 OMG IDL のデータ型でサポートされるさまざまな演算子について説明しています。表 13-3 で示すように、代入演算子はすべてのデータ型でサポートされるので、比較には含まれていません。
OMG IDL のデータ型 |
operator -> |
operator[ ] |
---|---|---|
|
あり |
なし |
|
あり |
なし |
|
あり |
あり (const を除く) |
|
なし |
あり |
表 13-4 では、シグニチャを示します。
シーケンス 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-3 で示すように、代入演算子はすべてのデータ型でサポートされるので、比較には含まれていません。
OMG IDL のデータ型 |
operator -> |
operator[ ] |
---|---|---|
|
あり |
なし |
|
あり |
なし |
|
あり |
あり (const を除く) |
|
なし |
あり |
表 13-6 では、シグニチャを示します。
out クラスの使い方
TYPE
_var
を out
パラメータとして渡すと、参照先だった前の値はすべて暗黙的に削除する必要があります。この要件を満たす ORB フックを付与するために、各 T_var
型には対応する TYPE
_out
型があります。この型は、out
パラメータ型としてのみ使用します。
注記 プログラマは、_out
クラスを直接インスタンス化できません。そのため、_out
クラスは関数のシグニチャでのみ指定してください。
可変長型の TYPE
_out
型の一般的な形式は、次のとおりです。
// C++
classTYPE
_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_;
//
TYPE
_var からの代入は不可
void operator=(constTYPE
_var&):
};
最初のコンストラクタは、リファレンス・データ・メンバを T*&
引数にバインドし、ポインタをゼロ (0) ポインタ値に設定します。2 番目のコンストラクタは、リファレンス・データ・メンバを TYPE
_var
引数が保持するポインタにバインドし、ポインタで delete
を呼び出します。その際、型が String_out
の場合は string_free()
を、配列型 TYPE
が TYPE
_var
の場合は TYPE
_free()
を呼び出します。3 番目のコンストラクタはコピー・コンストラクタで、コンストラクタ引数のデータ・メンバによって参照される同じポインタにリファレンス・データ・メンバをバインドします。
ほかの TYPE
_out
から代入すると、TYPE
_out
引数によって参照される TYPE
*
がデータ・メンバにコピーされます。TYPE
*
のオーバーロードの代入演算子は、ポインタ引数をデータ・メンバに代入するだけです。代入を行っても、以前に保持されていたポインタはまったく削除されません。この意味で、TYPE
_out
型の動作は、TYPE
*
とまったく同じです。TYPE
*&
変換演算子は、データ・メンバを返します。ptr()
メンバ関数もデータ・メンバを返しますが、暗黙的な変換の実行を避ける場合に使用できます。オーバーロードの矢印演算子 (operator->()
) を使用すると、TYPE
*
データ・メンバが指すデータ構造体のメンバにアクセスできます。アプリケーションに準拠する場合、有効な非 NULL
TYPE
*
で TYPE
_out
が初期化済みでない限り、オーバーロードの operator->()
を呼び出すことはできません。
対応する TYPE
_var
型のインスタンスから、TYPE
_out
に代入することはできません。これは、アプリケーション開発者がコピーを行うかどうか、または TYPE
_var
が TYPE
_out
に代入できるよう、それが管理するポインタの所有権を返すかどうかを判定する方法がないためです。TYPE
_var
を TYPE
_out
にコピーするには、アプリケーションで次のように new
を使用する必要があります。
// C++
TYPE
_var t = ...;
my_out = newTYPE
(t.in()); // コピーのヒープ割り当て
通常、t
で呼び出される in()
関数は、const
TYPE
&
を返して、新しく割り当てられた T
インスタンスのコピー・コンストラクタを呼び出すことができるようにします。
また、TYPE
_var
を作成すると、T_out
パラメータで返されるよう、それが管理するポインタの所有権を返します。アプリケーションでは、次のように TYPE
_var::_retn()
関数を使用する必要があります。
// C++
TYPE
_var t = ...;
my_out = t._retn(); // t は所有権を返す。コピーは行われない
TYPE
_out
型は、アプリケーションで作成または破棄される汎用目的のデータ型としては機能しません。そのため、この型は必要なメモリ管理を適切に行う目的で、オペレーションのシグニチャの内部でのみ使用する型です。
オブジェクト・リファレンスの out パラメータ
_var
を out
パラメータとして渡すと、参照先の前の値はすべて暗黙的に解放する必要があります。この要件を満たす C++ マッピング・インプリメンテーションのフックを付与するために、オブジェクト・リファレンス型ごとに _out
型が生成されます。この型は、out
パラメータ型としてのみ使用します。たとえば、インターフェイス TYPE
の場合、オブジェクト・リファレンス型 TYPE
_ptr
、ヘルパ型 TYPE
_var
、および out
パラメータ型 TYPE
_out
が生成されます。オブジェクト・リファレンス _out
型の一般的な形式は次のとおりです。
// C++
classTYPE
_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; }
operatorTYPE
_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_var
を out
パラメータとして渡すと、参照先の前の値はすべて暗黙的に解放する必要があります。この要件を満たす 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_;
// String_var からの代入は不可
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; // 不可、次のどちらかで指定
out = string_dup(s); // 1:コピー、または
out = s._retn(); // 2:借用
}
コメントで「1」とマークされた行の場合、呼び出し側は String_var
が所有する文字列を明示的にコピーし、結果を out
引数に代入しています。また、呼び出し側は、コメントで「2」とマークされた行で示すように、String_var
に文字列の所有権を強制的に放棄させるというテクニックも使用できます。これにより、メモリ管理のエラーを発生させずに out
引数に文字列を返すことができます。
引数の受け渡しの考慮事項
パラメータ渡しモードのマッピングでは、効率性と簡便性の両方のバランスを調整します。プリミティブ型、列挙、およびオブジェクト・リファレンスの場合、モードは単純で、プリミティブと列挙用の型 P
、およびインターフェイス型 A 用の型 A_ptr
を渡します。
集約型は複雑です。これは、いつ、どのようにパラメータのメモリを割り当てるか、または割り当て解除するかという問題があるためです。in
パラメータのマッピングは単純です。これは、パラメータの記憶域が呼び出し側によって割り当てられ、読み取り専用であるためです。out
パラメータと inout
パラメータのマッピングは、ほかと比較して問題が多くあります。可変長型の場合、呼び出し先は記憶域の一部またはすべてを割り当てる必要があります。呼び出し側の割り当てという点では、3 つの浮動小数点値のメンバを格納する構造体として表される Point 型など、固定長型の方がスタック割り当てが可能なので好ましいと言えます。
両方の割り当て方法に対応するために、分割割り当てで生じる可能性のある混同を未然に排除します。また、コピーを実行するときに、マッピングで固定長の集約体 T
用の T&
と、可変長の T
用の T*&
との間に混同が生じないようにする必要があります。このような手法を採る理由は、構造体が固定長か可変長かによって構造体の形式が異なることにあります。ただし、呼び出し側が管理対象の型 T_var
を使用する場合でも、マッピングは T_var&
で一貫しています。
out
パラメータと inout
パラメータのマッピングでは、T_var
が渡されるときにパラメータ内の以前の可変長データをすべて割り当て解除する必要があります。これらのパラメータの初期値がオペレーションに送信されない場合でも、BEA 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); // 最初の結果は解放
S *sp; // out に渡す前の初期化は不要
f(sp);
// use sp
delete sp; // 次の呼び出しで古い値が解放されることは想定不可能
f(sp);
out
パラメータと inout
パラメータの前の値を暗黙的に割り当て解除できるのは、T_var
型だけです。
// IDL
void q(out string s);
// C++
char *s;
for (int i = 0; i < 10; i++)
q(s); // メモリ・リーク
ループ内で q
関数を呼び出すたびに、メモリ・リークが発生します。これは、呼び出し側が out
結果で string_free
を呼び出していないことが原因です。これを修正するには、次に示す 2 つの方法があります。
// C++
char *s;
String_var svar;
for (int i = 0 ; i < 10; i++) {
q(s);
string_free(s); // 明示的な割り当て解除
// または
q(svar); // 暗黙的な割り当て解除
}
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 = /* 新しいデータ */;
A_var obj_tmp = obj;
obj = /* 新しいインターフェイス */
}
パラメータがポインタ (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++ では関数で配列を返すことができないためです。
マッピングは、配列のスライスへのポインタを返します。
配列のスライスとは、指定された元の配列の最初のサイズを除いたすべてのサイズを持つ配列のことです。
注記 データ型 object reference ptr には、擬似オブジェクト・リファレンスも含まれています。配列スライスの戻り値は、元の配列の最初のサイズを除いたすべてのサイズを持つ配列です。
呼び出し側は、in
引数として渡される引数すべてに記憶域を提供する必要があります。
注記 データ型 object reference var には、擬似オブジェクト・リファレンスも含まれています。
表 13-9 および 表 13-10 では、inout
パラメータと out
パラメータに関連付けられた記憶域、および戻り値の結果に対する呼び出し側の作業について説明します。
型 |
inout |
out |
戻り値の結果 |
---|---|---|---|
short |
1 |
1 |
1 |
long |
1 |
1 |
1 |
unsigned short |
1 |
1 |
1 |
unsigned long |
1 |
1 |
1 |
float |
1 |
1 |
1 |
double |
1 |
1 |
1 |
boolean |
1 |
1 |
1 |
char |
1 |
1 |
1 |
wchar |
1 |
1 |
1 |
octet |
1 |
1 |
1 |
enum |
1 |
1 |
1 |
object reference ptr |
2 |
2 |
2 |
struct (固定長) |
1 |
1 |
1 |
struct (可変長) |
1 |
3 |
3 |
union (固定長) |
1 |
1 |
1 |
union (可変長) |
1 |
3 |
3 |
string |
4 |
3 |
3 |
wstring |
4 |
3 |
3 |
sequence |
5 |
3 |
3 |
array (固定長) |
1 |
1 |
6 |
array (可変長) |
1 |
6 |
6 |
any |
5 |
3 |
3 |
![]() |
![]() |
![]() |
|
Copyright © 2001, BEA Systems, Inc. All rights reserved.
|