Tuxedo CORBA プログラミング リファレンス

     前  次    新しいウィンドウで目次を開く     
ここから内容の開始

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 にマッピングされます。

表 13-1 OMG IDL および C++ の基本データ型
OMG IDL
C++
C++ Out 型
short
CORBA::Short
CORBA::Short_out
long
CORBA::Long
CORBA::Long_out
unsigned short
CORBA::UShort
CORBA::UShort_out
unsigned long
CORBA::ULong
CORBA::ULong_out
float
CORBA::Float
CORBA::Float_out
double
CORBA::Double
CORBA::Double_out
char
CORBA::Char
CORBA::Char_out
boolean
CORBA::Boolean
CORBA::Boolean_out
octet
CORBA::Octet
CORBA::Octet_out
wchar
CORBA::WChar
CORBA::WChart_out

注意 : 長精度型 (long) が 64 ビットのマシンでも、CORBA::Long の定義は 32 ビット整数を参照します。

複雑なデータ型

表 13-2 に、オブジェクト、擬似オブジェクト、およびユーザ定義型のマッピングを示します。

表 13-2 オブジェクト、擬似オブジェクト、およびユーザ定義の OMG IDL と C++ の型
OMG IDL
C++
Object
CORBA::Object_ptr
struct
C++ struct
union
C++ class
enum
C++ enum
string
char*
wstring
CORBA::WChar *
sequence
C++ class
array
C++ array

文字列および 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};
};

次に、前の例で定義した 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 クラスにマッピングされます。

その他のデータ型については、表 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 番目の関数 (アクセサ) では、ユニオンの値を返しています。

ユニオン メンバーのデータ型によっては、モディファイア関数が追加生成されます。各データ型に対して生成されるメンバー関数は次のとおりです。

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); // メンバー「s」を選択
st = u.s(); // st == 1296
u._d(2); // OK : メンバー「s」がまだ選択されている
st = u.s(); // st == 1296
u._d(3); // BAD_PARAM : 別のメンバーを選択
ユニオンの新しいインスタンスで _d() モディファイアが呼び出されると、Tuxedo C++ の「暗黙的な切替」の制約が緩和されます。この場合、例外は送出されず、ユニオンへの影響はありません。
U u2;
u2._d(1); // 例外なし、ユニオンの変更もなし
st = u2.s(); // error! accessing an uninitialized union
u2.it(1296); // OK : これでメンバー「it」が選択された

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++ クラスには、次のものが格納されています。

生成されるクラスは可変長構造体と似ています。ただし、このクラスは初期化を簡単にするためのコンストラクタ、および 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 仕様における、両者の基本的な違いは次のとおりです。

サーバレス オブジェクトへのリファレンスは、アドレス空間などのコンピュータ間のコンテキストで有効とは限りません。代わりに、パラメータとして渡されるサーバレス オブジェクトへのリファレンスでは、このリファレンスの受信側が使用するオブジェクトの、非依存的で機能的に同じコピーが作成されます。これをサポートするには、データ レイアウトなど、サーバレス オブジェクトのほかの隠れた表現プロパティを ORB に認識させます。この章では、ORB にサーバレス オブジェクトを認識させる仕様については、実装上の詳細事項のため説明は割愛します。

この章では、代わりにすべての擬似オブジェクト型の標準的なマッピング アルゴリズムについて説明します。これにより、9 種類の CORBA 擬似オブジェクト型ごとのマッピングについて、説明が断片的にならずに済み、CORBA の将来のリビジョンで提供される可能性のある擬似オブジェクト型にも対応できます。また、C マッピングの表現に依存せずに、C 互換の表現に依存した実装を実現することができます。

形式

C PIDL とは異なり、このマッピングでは、完全な OMG IDL の拡張形式を使用してサーバレス オブジェクト型を記述します。擬似オブジェクト型のインタフェースでは、通常の OMG IDL インタフェースと同じ規則に従います。ただし、次の例外があります。

pseudo 接頭辞は、そのインタフェースが通常の方法またはサーバレスの方法のどちらかで実装されることを示します。つまり、以降のセクションで説明する規則か、またはこのセクションで説明する通常のマッピング規則のどちらかを適用することになります。

マッピング規則

サーバレス オブジェクトは、このセクションで概説する相違点を除いて、通常のインタフェースと同じ方法でマッピングされます。

サーバレス オブジェクト型を表すクラスはCORBA::Object のサブクラスではありません。また、ほかの C++ クラスのサブクラスである必要はありません。したがって、Object::create_request などのオペレーションを必ずしもサポートしません。

サーバレス オブジェクト型の T を表す各クラスの場合、次の関数のオーバーロードの各バージョンが CORBA ネームスペースで提供されます。

// C++
void release(T_ptr);
Boolean is_nil(T_ptr p);

サブクラスは実装で提供できます。ただし、マッピングされた C++ クラスは、ユーザが容易にサブクラス化できるという保証はありません。実装では、サブクラスに適用されない内部表現や転送形式を想定することは可能です。

サーバレス オブジェクト型を表すクラスのメンバー関数は、通常のメモリ管理規則に従うとは限りません。これは、CORBA::NVList などの一部のサーバレス オブジェクトが、本質的にほかのサーバレス オブジェクトのいくつかのレベルのコンテナでしかない場合があるためです。格納されたサーバレス オブジェクトのアクセサ関数から返された値を、呼び出し側が明示的に解放しなければならないということは、本来の目的とは反対の使い方になってしまいます。

マッピングのその他の要素はすべて、次に示すように同じです。

C PIDL マッピングとの関係

サーバレス オブジェクトのインタフェースと宣言がこれらに依存する場合、すべて C マッピングに直接類似しています。マッピングされた C++ クラスは、必要に応じて、C マッピング用に選択したクラスと互換性のある表現を使用して実装することができます。C PIDL と C++ PIDL の擬似オブジェクト仕様の相違点は次のとおりです。

以降のセクションでは、各擬似インタフェースとその C++ マッピングの概説と一覧を示します。以下で定義が行われない型も含め、詳細については、このマニュアルの関連するセクションを参照してください。

Typedef

OMG IDL の typedef は、C++ の typedef にマッピングされます。OMG IDL のデータ型によっては、追加の typedef およびメンバー関数が定義される場合もあります。各データ型に対して生成されるコードは次のとおりです。

インタフェースの実装

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::AMod::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++ コードを生成すると、Oracle Tuxedo OMG IDL コンパイラでは、その情報を伝えるメッセージが出力されます。このメッセージを無視して、インタフェースまたは型とモジュール名とを区別するために一意の名前を付けなかった場合、コンパイラによってファイルの生成時にエラーが発生したことが通知されます。

インタフェース

OMG IDL のインタフェースは、C++ のクラスにマッピングされます。このクラスは、OMG IDL インタフェース内にあるオペレーション、属性、定数、およびユーザ定義の型 (UDT) を格納します。

インタフェース INTF の場合、生成されるインタフェース コードには、次の項目が格納されます。

次に、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++ 関数にマッピングされます。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++ の型は別々のものである必要があります。ただし、この要件が満たされない特別な場合があります。

Any への挿入

型保障の方法で any の値を設定できるようにするために、OMG IDL の型 T ごとに次のオーバーロード演算子関数が個別に用意されています。

// C++
void operator<<=(Any&, T);

この関数のシグネチャでは、次の型があれば十分です。通常、これらの型は値によって渡されます。

型 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 の値を設定することは、次のことを意味します。

文字列型の挿入をコピーすると、次の関数が呼び出されます。

// 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_foranynocopy フラグは、挿入された値をコピーするか (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;
// ... s を初期化 ...
Any a;
a <<= s; // 行 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*&);

この関数の最初の形式は、次の型にのみ使用されます。

その他の型については、すべて関数の 2 番目の形式が使用されます。

上記の「右シフト代入」演算子は、次のように型付き値を any から抽出するために使用します。

// C++
Long value;
Any a;
a <<= Long(42);
if (a >>= value) {
// ... 値を使用 ...
}

この場合、型 Longoperator>>= のバージョンは、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_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 インタフェースで定義するので、任意の実装が可能になります。分散オブジェクト システムでは、実装上の制約がほとんどないので、大きな値が入ります。ただし、リファレンスよりも値でオブジェクトを渡すことが可能な方が望ましい場合が多くあります。これは、オブジェクトの主要な「目的」がデータをカプセル化する場合や、アプリケーションでオブジェクトの「コピー」を明示的に作成するのが好ましい場合に、特に便利です。

値でオブジェクトを渡すセマンティクスは、標準のプログラミング言語のセマンティクスとほぼ同じです。値で渡されるパラメータの受信側は、オブジェクトの「状態」の記述を受信します。次に、受信側は新しいインタンスをその状態でインスタンス化します。その際、送信側のインスタンスの 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();
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:
// プライベートおよび未実装
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*);
      // ...
};

 


固定長ユーザ定義型と可変長ユーザ定義型

ユーザ定義型のメモリ管理規則およびメンバー関数のシグネチャは、その型が固定長か可変長かどうかによって異なります。次のいずれか 1 つに該当する場合、ユーザ定義型は可変長です。

上記の一覧に型が該当しない場合、その型は固定長です。

 


var クラスの使い方

自動変数 var は、メモリ管理を簡単に行うために用意されています。var は var クラスを通じて提供されます。このクラスは、型に必要なメモリの所有権を想定し、var オブジェクトのインスタンスが破棄されたり、新しい値が var オブジェクトに割り当てられたときにメモリを解放します。

Oracle Tuxedo では、次の型の var クラスが用意されています。

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 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_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 で示す ininoutout、および基底の型 TYPE の戻り値モードの型にそれぞれ一致します。

ユーザ定義のデータ型によって、サポートされる演算子は一部異なります。表 13-3 では、生成された C++ コードにおける各 OMG IDL のデータ型でサポートされるさまざまな演算子について説明しています。表 13-3 で示すように、代入演算子はすべてのデータ型でサポートされるので、比較には含まれていません。

表 13-3 ユーザ定義のデータ型の var クラスでサポートされる演算子の比較
OMG IDL のデータ型
operator ->
operator[ ]
struct
あり
なし
union
あり
なし
sequence
あり
あり (const を除く)
array
なし
あり

表 13-4 では、シグネチャを示します。

表 13-4 _var クラスの演算子のシグネチャ
OMG IDL のデータ型
演算子メンバー関数
struct
TYPE * operator-> ()
TYPE * operator-> () const
union
TYPE * operator-> ()
TYPE * operator-> () const
sequence
TYPE * operator-> ()
TYPE * operator-> () const
TYPE & operator[](CORBA::Long index)
array
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-3 で示すように、代入演算子はすべてのデータ型でサポートされるので、比較には含まれていません。

表 13-5 ユーザ定義のデータ型の out クラスでサポートされる演算子の比較
OMG IDL のデータ型
operator ->
operator[ ]
struct
あり
なし
union
あり
なし
sequence
あり
あり (const を除く)
array
なし
あり

表 13-6 では、シグネチャを示します。

表 13-6 _out クラスの演算子のシグネチャ
OMG IDL のデータ型
演算子メンバー関数
struct
TYPE * operator-> ()
TYPE * operator-> () const
union
TYPE * operator-> ()
TYPE * operator-> () const
sequence
TYPE * operator-> ()
TYPE * operator-> () const
TYPE & operator[](CORBA::Long index)
array
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_;
     // TYPE_var からの代入は不可
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->() を呼び出すことはできません。

対応する TYPE_var 型のインスタンスから、TYPE_out に代入することはできません。これは、アプリケーション開発者がコピーを行うかどうか、または TYPE_varTYPE_out に代入できるよう、それが管理するポインタの所有権を返すかどうかを判定する方法がないためです。TYPE_varTYPE_out にコピーするには、アプリケーションで次のように new を使用する必要があります。

// C++
TYPE_var t = ...;
my_out = new
TYPE(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 パラメータ

_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_;
     // 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 が渡されるときにパラメータ内の以前の可変長データをすべて割り当て解除する必要があります。これらのパラメータの初期値がオペレーションに送信されない場合でも、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);
// s を使用
f(s); // 最初の結果は解放

S *sp; // out に渡す前の初期化は不要
f(sp);
// 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 = /* new data */;
A_var obj_tmp = obj;
obj = /* new reference */
}

パラメータがポインタ (T*) またはポインタ (T*&) へのリファレンスとして受け渡しされる場合、アプリケーションは NULL ポインタを受け渡しすることができません。これを実行すると、結果は未定義になります。特に、次のどちらかに該当する場合、呼び出し側は NULL ポインタを渡すことができません。

ただし、呼び出し側は、out パラメータの NULL 値でポインタへのリファレンスを渡すことはできます。これは、呼び出し先が値を確認せずに上書きするためです。呼び出し先は、次のいずれかに該当する場合、NULL ポインタを渡すことができません。

オペレーションのパラメータおよびシグネチャ

表 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++ では関数で配列を返すことができないためです。マッピングは、配列のスライスへのポインタを返します。
配列のスライスとは、指定された元の配列の最初のサイズを除いたすべてのサイズを持つ配列のことです。

表 13-7 基本的な引数と結果の受け渡し
データ型
In
Inout
Out
戻り値
short
Short
Short&
Short&
Short
long
Long
Long&
Long&
Long
unsigned short
UShort
UShort&
UShort&
UShort
unsigned long
ULong
ULong&
ULong&
ULong
float
Float
Float&
Float&
Float
double
Double
Double&
Double&
Double
boolean
Boolean
Boolean&
Boolean&
Boolean
char
Char
Char&
Char&
Char
wchar
WChar
WChar&
WChar
Octet
octet
Octet
Octet&
Octet&
Octet
enum
enum
enum&
enum&
enum
object reference ptr (下記の注意を参照)
objref_ptr
objref_ptr&
objref_ptr&
objref_ptr
struct (固定長)
const struct&
struct&
struct&
struct
struct (可変長)
const struct&
struct&
struct*&
struct*
union (固定長)
const union&
union&
union&
union
union (可変長)
const union&
union&
union*&
union*
string
const char*
char*&
char*&
char*
wstring
const WChar
WChar*&
Wchar*&
WChar*
sequence
const sequence&
sequence&
sequence*&
sequence*
array (固定長)
const array
array
array
array slice* (下記の注意を参照)
array (可変長)
const array
array
array slice*&
array slice*
any
const any&
any&
any*&
any*

注意 : データ型 object reference ptr には、擬似オブジェクト参照も含まれています。配列スライスの戻り値は、元の配列の最初のサイズを除いたすべてのサイズを持つ配列です。

呼び出し側は、in 引数として渡される引数すべてにストレージを提供する必要があります。

表 13-8 T_var の引数と結果の受け渡し
データ型
In
Inout
Out
戻り値
object reference var (下記の注意を参照)
const objref_var&
objref_var&
objref_var&
objref_var
struct_var
const struct_var&
struct_var&
struct_var&
struct_var
union_var
const union_var&
union_var&
union_var&
union_var
string_var
const string_var&
string_var&
string_var&
string_var
sequence_var
const sequence_var&
sequence_var&
sequence_var&
sequence_var
array_var
const array_var&
array_var&
array_var&
array_var
any_var
const any_var&
any_var&
any_var&
any_var

注意 : データ型 object reference var には、擬似オブジェクト参照も含まれています。

表 13-9 および 表 13-10 では、inout パラメータと out パラメータに関連付けられたストレージ、および戻り値の結果に対する呼び出し側の作業について説明します。

表 13-9 引数のストレージに対する呼び出し側の作業
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

表 13-10 引数の受け渡しのケース
ケース
 
1
呼び出し側は必要なストレージをすべて割り当てます。ただし、パラメータ自体の中でカプセル化および管理できるストレージは除きます。inout パラメータの場合、呼び出し側は初期値を指定し、呼び出し先はその値を変更できます。out パラメータの場合、呼び出し側はストレージを割り当てますが初期化する必要はなく、呼び出し先が値を設定します。関数は値で戻り値を返します。
2
呼び出し側は、オブジェクト参照のストレージを割り当てます。inout パラメータの場合、呼び出し側は初期値を指定します。呼び出し先が inout パラメータを再割り当てする場合は、まず、元の入力値で CORBA::release を呼び出します。inout として渡されたオブジェクト参照を引き続き使用するには、呼び出し側は最初にリファレンスを複製する必要があります。そして、out をすべて解放してから、オブジェクト参照を返します。ほかの構造体に埋め込まれたオブジェクト参照はすべて、各構造体自体によって自動的に解放されます。
3
out パラメータの場合、呼び出し側はポインタを割り当て、リファレンスでそれを呼び出し先に渡します。呼び出し先は、パラメータの型の有効なインスタンスを指すようにポインタを設定します。戻り値の場合は、呼び出し先は同様のポインタを返します。どちらの場合でも、呼び出し先は NULL ポインタを返すことはできません。
どちらの場合でも、呼び出し側は戻り値のストレージを解放する必要があります。ローカルまたはリモートの透過性を維持するには、呼び出し先が呼び出し側と同じアドレス空間にあるか、異なるアドレス空間にあるかどうかに関係なく、呼び出し側は常に戻り値のストレージを解放しなければなりません。要求が完了した後は、呼び出し側は戻り値のストレージの値を変更することはできません。これを行う場合は、呼び出し側は最初に戻り値のインスタンスを新しいインスタンスにコピーしてから、新しいインスタンスを変更する必要があります。
4
inout 文字列の場合、呼び出し側は、入力文字列とそれを指す char* の両方にストレージを割り当てます。呼び出し先が入力文字列の割り当てを解除し、新しいストレージを指す char* を再割り当てして出力値を保持する可能性があるため、呼び出し側は string_alloc() を使用して入力文字列を割り当てる必要があります。そのため、out 文字列のサイズは in 文字列のサイズに制限されません。呼び出し側は、string_free() を使用して out のストレージを削除する必要があります。呼び出し先は、inoutout、または戻り値に対して NULL ポインタを返すことはできません。
5
inout シーケンスおよび any の場合、シーケンスまたは any を作成した Boolean 解放パラメータの状態によっては、シーケンスまたは any を割り当てまたは変更することにより、再割り当てが行われる前に、所有しているストレージの割り当てが解除される場合があります。
6
out パラメータの場合、呼び出し側は配列スライス (元の配列の最初のサイズを除いたすべてのサイズを持つ配列) へのポインタを割り当て、リファレンスでポインタを呼び出し先に渡します。呼び出し先は、配列の有効なインスタンスを指すようにポインタを設定します。
戻り値の場合は、呼び出し先は同様のポインタを返します。どちらの場合でも、呼び出し先は NULL ポインタを返すことはできません。どちらの場合でも、呼び出し側は戻り値のストレージを解放する必要があります。
ローカルまたはリモートの透過性を維持するには、呼び出し先が同じアドレス空間にあるか、異なるアドレス空間にあるかどうかに関係なく、呼び出し側は常に戻り値のストレージを解放しなければなりません。要求が完了した後は、呼び出し側は戻り値のストレージの値を変更することはできません。これを行う場合は、呼び出し側は最初に戻り値の配列インスタンスを新しい配列インスタンスにコピーしてから、新しいインスタンスを変更する必要があります。

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


  ページの先頭       前  次