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

     前  次    新規ウィンドウで目次を開く  新規ウィンドウで索引を開く  PDFとして表示 - 新規ウィンドウ  Adobe Readerを取得 - 新規ウィンドウ
コンテンツはここから始まります

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
{
// Fixed-length
struct Date
{
long year;
long month;
long day;
};

// Variable-length
struct Address
{
string aptNum;
string streetName;
string city;
string state;
string zipCode;
};
};

上の定義は、次のようにC++にマッピングされます。

    // C++
    class INVENT
{
struct Date
{
CORBA::Long year;
CORBA::Long month;
CORBA::Long day;
};
         struct  Address
{
CORBA::String_var aptNum;
CORBA::String_var streetName;
CORBA::String_var city;
CORBA::String_var state;
CORBA::String_var zipCode;
Address &operator=(const Address &_obj);
};

};

メンバーのマッピング

構造体のメンバーは、適切なC++データ型にマッピングされます。long、shortなどの基本データ型については、表13-1を参照してください。オブジェクト参照、擬似オブジェクト参照、および文字列については、メンバーは次の適切なvarクラスにマッピングされます。

その他のデータ型については、表13-2を参照してください。

生成される構造体にはコンストラクタがないため、メンバーは初期化されません。固定長構造体の場合、集約初期化を行うと初期化できます。例:

INVENT::Date a_date = { 1995, 10, 12 };

可変長メンバーの場合、自己管理型にマッピングします。この型には、メンバーを初期化するコンストラクタが含まれています。

Var

構造体に対してvarクラスが生成されます。詳細は、「varクラスの使い方」を参照してください。

Out

構造体に対してoutクラスが生成されます。詳細は、「outクラスの使い方」を参照してください。

ユニオン

OMG IDLのユニオンは、C++のクラスにマッピングされます。C++クラスには、次のものが格納されています。

次に、OMG IDL定義の例を示します。

    // OMG IDL
    union OrderItem switch (long)
{
case 1: itemStruct itemInfo;
case 2: orderStruct orderInfo;
default: ID idInfo;
};

上の定義は、次のようにC++にマッピングされます。

    // C++
   class OrderItem
{
public:
OrderItem();
OrderItem(const OrderItem &);
~OrderItem();

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

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

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

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

. . .
};

デフォルトのユニオン・コンストラクタでは、ユニオンのデフォルト区別子の値が設定されていません。そのため、ユニオンの値を設定するまでは、すべてのユニオン・アクセサ・メンバー関数を呼び出すことができません。区別子は、_dメンバー関数でマッピングされる属性です。

ユニオン・メンバーのアクセサ・メンバー関数とモディファイア・メンバー関数のマッピング

ユニオンのメンバーごとに、アクセサ・メンバー関数とモディファイア・メンバー関数が生成されます。

前の例から抜粋した次のコードでは、2つのメンバー関数はIDメンバー関数に対して生成されています。

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

この例では、最初の関数(モディファイア)で区別子をデフォルト値に、ユニオンの値を指定のID値に設定しています。2番目の関数(アクセサ)では、ユニオンの値を返しています。

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

Var

ユニオンに対してvarクラスが生成されます。詳細は、「varクラスの使い方」を参照してください。

Out

ユニオンに対してoutクラスが生成されます。詳細は、「outクラスの使い方」を参照してください。

メンバー関数

アクセサとモディファイアのほかに、型TYPEのOMG IDLユニオンに対してswitch (long)区別子で次のメンバー関数が生成されます。

TYPE();

これは、ユニオンのデフォルト・コンストラクタです。この関数ではデフォルトの区別子が設定されないため、ユニオンの値を設定するまではユニオンにアクセスできません。

TYPE( const TYPE & From);

このコピー・コンストラクタは、指定のユニオンをディープ・コピーします。ユニオン・パラメータの任意の値をコピーします。From引数には、コピー元のユニオンを指定します。

~TYPE();

このデストラクタは、ユニオンに関連付けられたデータを解放します。

TYPE &operator=(const TYPE & From);

この代入演算子は指定のユニオンをコピーします。現在のユニオンにある既存の値は解放されます。From引数には、コピー元のユニオンを指定します。

void _d (CORBA::Long Discrim);

このモディファイアは、ユニオン区別値の値を設定します。Discrim引数には、新しい区別値を指定します。引数のデータ型は、ユニオンのswitch文で指定したOMG IDLのデータ型で決まります。OMG IDLおよびC++の各データ型については、表13-1を参照してください。
この関数は、同じユニオン・メンバー内の値に区別値を設定する場合にのみ使用します。この関数を使用して、ユニオン・メンバーを暗黙的に切り替えることはできません。 これらの制約については、次のコードを参照してください。
union U switch(long) {
case 1:
case 2:
short s;
case 3:
int it;
};

short st;
U u;
u.s(1296); // member "s" selected
st = u.s(); // st == 1296
u._d(2); // OK: member "s" still selected
st = u.s(); // st == 1296
u._d(3); // BAD_PARAM: selecting a different member
ユニオンの新しいインスタンスで_d()モディファイアが呼び出されると、Tuxedo C++の「暗黙的な切替」の制約が緩和されます。この場合、例外はスローされず、ユニオンへの影響はありません。
U u2;
u2._d(1); // no exception, union is unchanged
st = u2.s(); // error! accessing an uninitialized union
u2.it(1296); // OK: member "it" now selected

CORBA::Long _d () const;

この関数は現在の区別値を返します。戻り値のデータ型は、ユニオンのswitch文で指定したOMG IDLのデータ型で決まります。OMG IDLおよびC++の各データ型については、表13-1を参照してください。

シーケンス

OMG IDLのシーケンスは、C++のクラスにマッピングされます。C++クラスには、次のものが格納されています。

要素にアクセスする場合、事前に長さを設定しておく必要があります。

次に、OMG IDL定義の例を示します。

// OMG IDL
module INVENT 
{
. . .
typedef sequence<LogItem> LogList;
}

上の定義は、次のようにC++にマッピングされます。

// C++
class LogList
{
public:
// Default constructor
LogList();
        // Maximum constructor
LogList(CORBA::ULong _max);
       // TYPE * data constructor
LogList
(
CORBA::ULong _max,
CORBA::ULong _length,
LogItem *_value,
CORBA::Boolean _relse = CORBA_FALSE
);
        // Copy constructor
LogList(const LogList&);
        // Destructor 
~LogList();
        LogList &operator=(const LogList&);
        CORBA::ULong maximum() const;
        void length(CORBA::ULong);
CORBA::ULong length() const;
        LogItem &operator[](CORBA::ULong _index);
const LogItem &operator[](CORBA::ULong _index) const;
        static LogItem *allocbuf(CORBA::ULong _nelems);
static void freebuf(LogItem *);
};
    };

シーケンス要素のマッピング

operator[]関数は、シーケンス要素へのアクセスまたはシーケンス要素の変更に使用します。この演算子は、シーケンス要素にリファレンスを返します。OMG IDLのベース・タイプは、C++の適切なデータ型にマッピングされます。

基本データ型については、表13-1を参照してください。オブジェクト参照、TypeCodeリファレンス、および文字列の場合、ベース・タイプは生成された_ForSeq_varクラスにマッピングされます。_ForSeq_varクラスは、文字列またはシーケンス内に格納されたオブジェクトを更新する機能を備えています。このクラスには、対応するvarクラスと同じメンバー関数とシグネチャがあります。ただし、_ForSeq_varクラスは、シーケンス・コンストラクタのreleaseパラメータの設定に従います。ほかのクラスとの相違点は、_ForSeq_varクラスの場合、ユーザーがReleaseフラグを指定できるので、メモリーの解放を制御できることです。

その他のデータ型については、表13-2を参照してください。

Var

シーケンスに対してvarクラスが生成されます。詳細は、「varクラスの使い方」を参照してください。

Out

シーケンスに対してoutクラスが生成されます。詳細は、「outクラスの使い方」を参照してください。

メンバー関数

以下では、ベース・タイプがTYPEで指定のOMG IDLシーケンスがSEQの場合に、生成されるシーケンス・クラスのメンバー関数について説明します。

SEQ ();

これは、シーケンスのデフォルト・コンストラクタです。長さは0 (ゼロ)に設定されています。シーケンスが無制限の場合でも、最大値は0 (ゼロ)に設定されます。シーケンスが制限付きの場合は、最大値はOMG IDLの型で指定され、変更はできません。

SEQ (CORBA::ULong Max);

このコンストラクタは、シーケンスが無制限の場合にのみ指定します。この関数は、シーケンスの長さを0 (ゼロ)に設定し、バッファの最大値を指定の値に設定します。Max引数には、シーケンスの最大長を指定します。

SEQ (CORBA::ULong Max, CORBA::ULong Length, TYPE * Value,
CORBA::Boolean Release);

このコンストラクタは、シーケンスの最大値、長さ、および要素を設定します。シーケンスが破棄されたときに要素を解放するかどうかは、Releaseフラグで指定します。各引数について次に説明します。

Max

シーケンスの最大値。制限付きシーケンスでは、この引数はありません。

Length

シーケンスの現在の長さ。制限付きシーケンスの場合、この値はOMG IDLの型で指定した最大値より小さい値を指定する必要があります。

Value

シーケンスの要素を格納するバッファへのポインタ。

Release

要素を解放するかどうかを指定します。このフラグの値がCORBA_TRUEの場合、シーケンスはValue引数が指すバッファの所有権を想定します。ReleaseフラグがCORBA_ TRUEの場合、このバッファはallocbufメンバー関数で割り当てる必要があります。これは、シーケンスの破棄時に、このバッファをfreebufメンバー関数で解放するためです。

SEQ(const S& From);

このコピー・コンストラクタは、指定の引数からシーケンスをディープ・コピーします。From引数には、コピー元のシーケンスを指定します。

~SEQ();

このデストラクタは、シーケンスを解放します。また、Releaseフラグの値によっては、シーケンス要素を解放する場合もあります。

SEQ& operator=(const SEQ& From);

この代入演算子は、指定のシーケンス引数からシーケンスをディープ・コピーします。現在のシーケンスのReleaseフラグがCORBA_TRUEの場合、現在のシーケンスにある既存の要素はすべて解放されます。From引数には、コピー元のシーケンスを指定します。

CORBA::ULong maximum( ) const;

この関数は、シーケンスの最大値を返します。制限付きシーケンスの場合、OMG IDLの型で設定した値になります。無制限シーケンスの場合は、シーケンスの現在の最大値になります。

void length(CORBA::ULong Length);

この関数は、シーケンスの現在の長さを設定します。Length引数には、シーケンスの新しい長さを指定します。シーケンスが無制限で新しい長さが現在の最大値を超える場合、バッファが再割り当てされ、要素が新しいバッファにコピーされます。新しい長さが最大値を超える場合、最大値は新しい長さに設定されます。
制限付きシーケンスの場合は、最大値を超える値には長さを設定できません。

CORBA::ULong length() const;

この関数は、シーケンスの現在の長さを返します。

TYPE & operator[](CORBA::ULong Index);
const
TYPE & operator[](CORBA::ULong Index) const;

上記のアクセサ関数は、指定の索引でシーケンス要素へのリファレンスを返します。Index引数には、戻り値となる要素の索引を指定します。この索引は、現在のシーケンスの長さを超えることはできません。長さは、TYPE *コンストラクタまたはlength(CORBA::ULong)モディファイアで設定済みである必要があります。TYPEがオブジェクト参照、TypeCodeリファレンス、または文字列の場合、戻り値の型はForSeq_varクラスになります。

static TYPE * allocbuf(CORBA::ULong NumElems);

この静的関数は、TYPE *コンストラクタで使用されるバッファを割り当てます。NumElems引数には、バッファ内の割り当てる要素数を指定します。バッファの割当てができない場合、NULLが返されます。
releaseがCORBA_TRUEに設定されていて、このバッファがTYPE *コンストラクタに渡されない場合は、freebufメンバー関数で解放する必要があります。

static void freebuf(TYPE * Value);

この静的関数は、allocbuf関数で割り当てられたTYPE *シーケンス・バッファを解放します。Value引数には、allocbuf関数で割り当てられたTYPE *バッファを指定します。0 (ゼロ)ポインタは無視されます。

配列

OMG IDLの配列は、C++の配列定義にマッピングされます。次に、OMG IDL定義の例を示します。

    // OMG IDL
    module INVENT 
{
. . .
typedef LogItem LogArray[10];
};

上の定義は、次のようにC++にマッピングされます。

    // C++
    module INVENT
{
. . .
typedef LogItem LogArray[10];
typedef LogItem LogArray_slice;
static LogArray_slice * LogArray_alloc(void);
static void LogArray_free(LogArray_slice *data);

};

配列のスライス

配列のスライスとは、元の配列の最初のサイズを除いたすべてのサイズを持つ配列のことです。配列で生成されたクラスのメンバー関数は、スライスへのポインタを使用して配列へのポインタを返します。スライスごとにtypedefが生成されます。

次に、OMG IDL定義の例を示します。

    // OMG IDL
typedef LogItem LogMultiArray[5][10];

上の定義は、次のようにC++にマッピングされます。

    // C++
typedef LogItem LogMultiArray[5][10];
typedef LogItem LogMultiArray_slice[10];

配列のサイズが1つの場合、配列スライスは型だけになります。たとえば、サイズが1つのlongの配列がある場合、配列スライスはCORBA::Longデータ型になります。

配列要素のマッピング

OMG IDLの配列の型は、構造体と同じ方法でC++の配列要素型にマッピングされます。詳細は、「メンバーのマッピング」を参照してください。

Var

配列に対してvarクラスが生成されます。詳細は、「varクラスの使い方」を参照してください。

Out

配列に対してoutクラスが生成されます。詳細は、「outクラスの使い方」を参照してください。

割当てメンバー関数

各配列には、配列の割り当ておよび割当て解除を行う2つの静的関数があります。指定のOMG IDLの型TYPEの場合、割当てルーチンと割当て解除ルーチンは次のとおりです。

static TYPE_slice * TYPE_alloc(void);

この関数は、TYPE配列を割り当て、割当て済みのTYPE配列へのポインタを返します。配列を動的に割り当てることができない場合、0 (ゼロ)を返します。

static void TYPE_free(TYPE_slice * Value);

この関数は、動的に割り当てられたTYPE配列を解放します。Value引数は、解放元の動的に割り当てられたTYPE配列へのポインタです。

例外

OMG IDLの例外は、C++のクラスにマッピングされます。C++クラスには、次のものが格納されています。

生成されるクラスは可変長構造体と似ています。ただし、このクラスは初期化を簡単にするためのコンストラクタ、およびUserExceptionの型を判別するための静的_narrowメンバー関数が追加されている点で異なります。

次に、OMG IDL定義の例を示します。

    // OMG IDL
    module INVENT
{
exception NonExist
{
ID BadId;
};
};

上の定義は、次のようにC++にマッピングされます。

    // C++
    class INVENT
{
. . .
        class NonExist : public CORBA::UserException
{
public:
static NonExist * _narrow(CORBA::Exception_ptr);
NonExist (ID _BadId);
NonExist ();
NonExist (const NonExist &);
~NonExist ();
NonExist & operator=(const NonExist &);
void _raise ();
ID BadId;
};
};

Exceptionクラスの属性(データ・メンバー)はパブリックなので、直接アクセスできます。

メンバーのマッピング

例外のメンバーは、構造体と同じ方法でマッピングされます。詳細は、「メンバーのマッピング」を参照してください。

例外メンバーはすべて、C++ではパブリック・データなので、直接アクセスできます。

Var

例外に対してvarクラスが生成されます。詳細は、「varクラスの使い方」を参照してください。

Out

例外に対してoutクラスが生成されます。詳細は、「outクラスの使い方」を参照してください。

メンバー関数

指定のOMG IDL例外TYPEの場合、生成されるメンバー関数は次のとおりです。

static TYPE * _narrow(CORBA::Exception_ptr Except);

この関数は、例外がTYPE例外にナロー変換できる場合に、TYPE例外へのポインタを返します。例外がナロー変換できない場合は、0 (ゼロ)を返します。TYPEポインタは、新しいクラスへのポインタではなく、 元の例外ポインタへの型付きポインタです。これは、Exceptパラメータが有効なかぎりにおいて有効です。

TYPE ( );

これは、例外のデフォルト・コンストラクタです。メンバーが固定長の場合、メンバーは初期化されません。可変長メンバーの場合、自己管理型にマッピングします。この型には、メンバーを初期化するコンストラクタが含まれています。

TYPE(member-parameters);

このコンストラクタには、例外のメンバーごとに引数があります。このコンストラクタは、各引数をコピーし、各引数のメモリーの所有権を想定しません。前の例外を作成すると、そのコンストラクタのシグネチャは次のようになります。
NonExist (ID _BadId);
例外のメンバーごとに引数が1つあります。型とパラメータ渡しのメカニズムは、Anyの挿入演算子と同じです。Anyの挿入演算子の詳細は、「Anyへの挿入」を参照してください。

TYPE (const TYPE & From);

このコピー・コンストラクタは、指定のTYPE例外引数からデータをコピーします。From引数には、コピー元の例外を指定します。

~TYPE ();

このデストラクタは、例外に関連付けられたデータを解放します。

TYPE &operator=(const TYPE & From);

この代入演算子は、指定のTYPE例外引数からデータをコピーします。From引数には、コピー元の例外を指定します。

void _raise ();

この関数によって、例外インスタンスが自己に対してスローされます。catch句は、 派生した型で例外インスタンスを捕捉できます。

擬似オブジェクトのC++へのマッピング

CORBA擬似オブジェクトは、通常のCORBAオブジェクトまたはサーバーレス・オブジェクトとして実装できます。CORBA仕様における、両者の基本的な違いは次のとおりです。

サーバーレス・オブジェクトへのリファレンスは、アドレス空間などのコンピュータ間のコンテキストで有効とはかぎりません。かわりに、パラメータとして渡されるサーバーレス・オブジェクトへのリファレンスでは、このリファレンスの受信側が使用するオブジェクトの、非依存的で機能的に同じコピーが作成されます。これをサポートするには、データ・レイアウトなど、サーバーレス・オブジェクトのほかの隠れた表現プロパティを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);
};

生成されたクライアント・アプリケーション・スタブには、スタブ・クラスに対して生成された次のコードが格納されます。

// ROUTINE NAME:    INVENT::Stub_Order::modifyOrder 
//
// FUNCTIONAL DESCRIPTION:
//
// Client application stub routine for operation
// modifyOrder.
// (Interface : Order)
INVENT::ItemList * INVENT::Stub_Order::modifyOrder (
const INVENT::ItemList & ModifyList)
{
. . .
}

引数のマッピング

オペレーションの各引数は、表13-1および表13-2で説明した、対応するC++の型にマッピングされます。

オペレーションでの引数のパラメータ渡しモードについては、表13-7および表13-8を参照してください。

オペレーションの実装

実装メンバー関数のシグネチャは、OMG IDLオペレーションのマッピングされたシグネチャです。クライアント側と異なり、サーバー側のマッピングでは、関数ヘッダーに適切な例外(throw)指定を含める必要があります。これにより、いつ無効な例外が発生したかをコンパイラで検出できるようになります。これは、ローカルC++からC++ライブラリへの呼出しを行う場合に必要です。この作業を行わない場合、呼出しでは有効な例外をチェックするラッパーを通過してしまいます。例:

// IDL
interface A
{
exception B {};
void f() raises(B);
};
// C++
class MyA : public virtual POA_A
{
public:
void f() throw(A::B, CORBA::SystemException);
...
};

すべてのオペレーションおよび属性が原因でCORBAシステム例外は発生するため、オペレーションにraises句がない場合でも、すべての例外指定でCORBA::SystemExceptionを含める必要があります。

メンバー関数内で、「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; // declare impl of A
A_ptr a = &my_a; // obtain its object reference
// by C++ derived-to-base conversion

上のようなコードは、ORB準拠の実装でサポートしていますが、必須ではありません。そのため、移植性はありません。移植性のある同等のコードでは、実装オブジェクトで_this()を呼び出し、未登録の場合は暗黙的にそれを登録して、そのオブジェクト参照を取得します。

// C++
MyImplOfA my_a; // declare impl of A
A_ptr a = my_a._this(); // obtain its object reference

PortableServer関数

POAに登録されたオブジェクトでは、オブジェクト識別子としてオクテット、特にPortableServer::POA::ObjectId型のシーケンスを使用します。ただし、C++のプログラマはオブジェクト識別子として文字列を使用することが多いため、C++マッピングでは、文字列のObjectIdへの変換、またはその逆の変換を行ういくつかの変換関数が用意されています。

// C++
namespace PortableServer
{
char* ObjectId_to_string(const ObjectId&);

ObjectId* string_to_ObjectId(const char*);
}

上記の関数は、パラメータ渡しおよびメモリー管理について、標準のC++マッピングの規則に準拠しています。

ObjectIdを文字列に変換したときに、文字列に正しくない文字(NULLなど)が生成された場合は、最初の2つの関数によってCORBA::BAD_PARAM例外がスローされます。

モジュール

OMG IDLのモジュールは、C++のクラスにマッピングされます。モジュールに格納されるオブジェクトは、このC++クラスの中で定義します。インタフェースと型もクラスにマッピングされるため、ネストされたC++クラスが生成されます。

次に、OMG IDL定義の例を示します。

     // OMG IDL
     module INVENT
{
interface Order
{
. . .
};
};

上の定義は、次のようにC++にマッピングされます。

     // C++
     class INVENT
{
. . .
class Order : public virtual CORBA::Object
{
. . .
}; // class Order
}; // class INVENT

ネストされたモジュールが複数ある場合は、複数のネストされたクラスが生成されます。モジュール内のオブジェクトはモジュール・クラスになります。インタフェース内のオブジェクトはインタフェース・クラスになります。

OMG IDLでは、モジュール、インタフェース、および型の名前を同じにすることができます。ただし、C++言語用のファイルを生成する場合、名前を同じにすることはできません。この制限が必要になるのは、OMG IDLの名前が同じ名前でネストされたC++クラスに生成される際に、これをC++コンパイラでサポートしていないためです。

注意: 現在のモジュール名と同じ名前のインタフェースまたは型でOMG IDLからC++コードを生成すると、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);
};

生成されたクライアント・アプリケーション・スタブには、スタブ・クラスに対して生成された次のコードが格納されます。

// ROUTINE NAME:       INVENT::Stub_Item::itemInfo 
//
// FUNCTIONAL DESCRIPTION:
//
// Client application stub routine for attribute
// INVENT::Stub_Item::itemInfo. (Interface : Item)
INVENT::itemStruct * INVENT::Stub_Item::itemInfo ( )
{
. . .
}
//
// ROUTINE NAME: INVENT::Stub_Item::itemInfo
//
// FUNCTIONAL DESCRIPTION:
//
// Client application stub routine for attribute
// INVENT::Stub_Item::itemInfo. (Interface : Item)
void INVENT::Stub_Item::itemInfo (
const INVENT::itemStruct & itemInfo)
{
}

引数のマッピング

属性は、属性値を返すオペレーションと属性を設定するオペレーションの2つのオペレーションと等価です。たとえば、上記のitemInfo属性は次と等価です。

void itemInfo (in itemStruct itemInfo); 
itemStruct itemInfo ();

属性の引数のマッピングは、オペレーションの引数のマッピングと同じです。属性は、対応する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&); // copying form
void operator<<=(Any&, T*); // non-copying form

コピー形式は、呼出し側に関して見れば、最初に示した形式とほぼ同じです。

上記の「左シフト代入」演算子は、次のように型付き値を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_foranyコンストラクタのnocopyフラグは、挿入された値をコピーするか(nocopy == FALSE)、処理するか(nocopy == TRUE)を制御するために使用します。nocopyフラグはデフォルトでFALSEに指定されているため、デフォルトでは挿入がコピーされます。

Tの配列とT*には型にあいまいさがあるため、移植性のあるコードの場合は、配列をAnyに挿入するときに適切なArray_forany型を明示的に使用することをお薦めします。例:

// IDL
struct S {... };
typedef S SA[5];
// C++
struct S { ... };
typedef S SA[5];
typedef S SA_slice;
class SA_forany { ... };

SA s;
// ...initialize s...
Any a;
a <<= s; // line 1
a <<= SA_forany(s); // line 2

行1の場合、配列型SAがその最初の要素へのポインタに集束されるため、コピーSA_forany挿入演算子ではなく、非コピーoperator<<=(Any&, S*)が呼び出されます。行2の場合、SA_forany型が明示的に作成されるので、目的の挿入演算子が呼び出されます。

オブジェクト参照のoperator<<=の非コピー・バージョンでは、次のようにT_ptr型のアドレスを取得します。

// IDL
interface T { ... };
// C++
void operator<<=(Any&, T_ptr); // copying
void operator<<=(Any&, T_ptr*); // non-copying

非コピーのオブジェクト参照の挿入では、T_ptr*が指すオブジェクト参照を処理します。したがって、Anyが元のオブジェクト参照を複製して直ちに解放するため、挿入後に呼出し側は、T_ptrが参照するオブジェクトにアクセスすることができません。呼出し側は、T_ptr自体のストレージの所有権を保持します。

operator<<=のコピー・バージョンは、Any_var型でもサポートされます。

Anyからの抽出

型保障の方法でanyから値を取得できるようにするために、ORBではOMG IDLの型Tごとに次の演算子が用意されています。

// C++
Boolean operator>>=(const Any&, T&);

この関数のシグネチャでは、プリミティブ型があれば十分です。通常、この型は値によって渡されます。型Tの値が大きすぎて完全に値を渡すことができない場合、ORBでは次のように別のシグネチャが提供されます。

// C++
Boolean operator>>=(const Any&, T*&);

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

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

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

// C++
Long value;
Any a;
a <<= Long(42);
if (a >>= value) {
// ... use the value ...
}

この場合、型Longoperator>>=のバージョンは、Anyが型Longの値を格納しているかどうかを判別します。格納している場合、呼出し側によって提供されたリファレンス変数にその値をコピーし、TRUEを返します。Anyが型Longの値を格納していない場合、呼出し側のリファレンス変数の値は変更されず、operator>>=FALSEを返します。

型が非プリミティブの場合、ポインタが抽出を行います。次に、OMG IDL構造体の例を示します。

// IDL
struct MyStruct {
long lmem;
short smem;
};

上記の構造体は、次のようにAnyから抽出できます。

// C++
Any a;
// ... a is somehow given a value of type MyStruct ...
MyStruct *struct_ptr;
if (a >>= struct_ptr) {
// ... use the value ...
}

抽出に成功した場合、呼出し側のポインタはAnyが管理するストレージを指し、operator>>=TRUEを返します。呼出し側は、このストレージのdeleteまたは解放を試行する必要はありません。また、代入、挿入、またはreplace関数によってAny変数が置き換えられた後、またはAny変数が破棄された後に、呼出し側はストレージを使用する必要もありません。ただし、これらの抽出演算子でT_var型を使用しないよう注意する必要があります。これは、Anyによって所有されるストレージを抽出演算子が削除しようとするためです。

抽出に失敗した場合、呼出し側のポインタの値はNULLポインタと同じに設定され、operator>>=FALSEを返します。

配列型を正しく抽出するには、Array_forany型を使用します。この型については、「配列」を参照してください。

次に、OMG IDLの例を示します。

// IDL
typedef long A[20];
typedef A B[30][40][50];
// C++
typedef Long A[20];
typedef Long A_slice;
class A_forany { ... };
typedef A B[30][40][50];
typedef A B_slice[40][50];
class B_forany { ... };

Boolean operator>>=(const Any&, A_forany&); // for type A
Boolean operator>>=(const Any&, B_forany&); // for type B

Array_forany型は、リファレンスによって常にoperator>>=に渡されます。

文字列および配列の場合、アプリケーションはAnyのTypeCodeをチェックします。これは、抽出値を使用する際に、アプリケーションが確実に配列オブジェクトまたは文字列オブジェクトのバウンドを超えないようにするためです。

operator>>=は、Any_var型でもサポートされます。

Boolean、Octet、Char、および制限付き文字列の識別

OMG IDLの型のBoolean、octet、およびcharは、特定のC++型にマッピングする必要はありません。そのため、型保障Anyインタフェースで使用できるようにするために、これらの型を互いに識別する方法が別に必要となります。同様に、制限付き文字列と無制限文字列は共にchar*にマッピングされるため、両者を識別する方法が別に必要となります。ここでは、識別を行うために、Anyクラス・インタフェース内でネストされた新しいヘルパー型をいくつか導入します。ヘルパー型を使用した識別の例を次に示します。

// C++
class Any
{
public:
// special helper types needed for boolean, octet,
// char, and bounded string insertion
struct from_boolean {
from_boolean(Boolean b) : val(b) {}
Boolean val;
};
struct from_octet {
from_octet(Octet o) : val(o) {}
Octet val;
};
struct from_char {
from_char(Char c) : val(c) {}
Char val;
};
struct from_string {
from_string(char* s, ULong b,
Boolean nocopy = FALSE) :
val(s), bound(b) {}
char *val;
ULong bound;
};
    void operator<<=(from_boolean);
void operator<<=(from_char);
void operator<<=(from_octet);
void operator<<=(from_string);
// special helper types needed for boolean, octet,
// char, and bounded string extraction
struct to_boolean {
to_boolean(Boolean &b) : ref(b) {}
Boolean &ref;
};
struct to_char {
to_char(Char &c) : ref(c) {}
Char &ref;
};
struct to_octet {
to_octet(Octet &o) : ref(o) {}
Octet &ref;
};
struct to_string {
to_string(char *&s, ULong b) : val(s), bound(b) {}
char *&val;
ULong bound;
};
    Boolean operator>>=(to_boolean) const;
Boolean operator>>=(to_char) const;
Boolean operator>>=(to_octet) const;
Boolean operator>>=(to_string) const;
    // other public Any details omitted
private:
// these functions are private and not implemented
// hiding these causes compile-time errors for
// unsigned char
void operator<<=(unsigned char);
Boolean operator>>=(unsigned char &) const;
};

ORBでは、これらの特別なヘルパー型用に、オーバーロードのoperator<<=およびoperator>>=関数を提供します。これらのヘルパー型は、次のように使用します。

// C++
Boolean b = TRUE;
Any any;
any <<= Any::from_boolean(b);
// ...
if (any >>= Any::to_boolean(b)) {
// ...any contained a Boolean...
}

char* p = "bounded";
any <<= Any::from_string(p, 8);
// ...
if (any >>= Any::to_string(p, 8)) {
// ...any contained a string<8>...
}

制限値が0 (ゼロ)の場合、無制限文字列を示します。

Anyへの制限付き文字列または無制限文字列の挿入をコピーせずに行う場合、from_stringコンストラクタでnocopyフラグをTRUEに設定する必要があります。

// C++
char* p = string_alloc(8);
// ...initialize string p...
any <<= Any::from_string(p, 8, 1); // any consumes p

boolean、charおよびoctetがすべてC++型のunsigned charにマッピングされる場合、boolean、charまたはoctet型のanyの直接挿入または抽出を試行すると、unsigned char用のプライベートで未実装のoperator<<=およびoperator>>=関数によって、コンパイル・エラーが発生します。

// C++
Octet oct = 040;
Any any;
any <<= oct; // this line will not compile
any <<= Any::from_octet(oct); // but this one will

Objectへの型の拡大

Anyからオブジェクト参照を基本Object型として抽出する方が望ましい場合があります。これを実行するには、boolean、char、およびoctetの抽出に必要なヘルパー型と同様のヘルパー型を使用します。

// C++
class Any
{
public:
...
struct to_object {
to_object(Object_ptr &obj) : ref(obj) {}
Object_ptr &ref;
;
Boolean operator>>=(to_object) const;
...
};

to_objectヘルパー型は、Anyからオブジェクト参照を基本Object型として抽出するために使用します。AnyにそのTypeCodeとして示されたオブジェクト参照型の値がある場合、抽出関数operator>>=(to_object)は、その格納されているオブジェクト参照を明示的にObject型に拡大し、TRUEを返します。それ以外の場合は、FALSEを返します。抽出されたオブジェクト参照の型の拡大を実行するのは、オブジェクト参照抽出関数のみです。通常のオブジェクト参照の抽出と同じく、to_object抽出演算子は、オブジェクト参照を複製しません。

型付けされていない値の処理

状況によっては、Anyへの型保障インタフェースでは不十分な場合があります。たとえば、データ型がバイナリ形式でファイルから読み取られ、型Anyの値を作成するために使用される状況などです。このような場合、Anyクラスは、コンストラクタに明示的なTypeCodeとジェネリック・ポインタを提供します。

// C++
Any(TypeCode_ptr tc, void *value, Boolean release = FALSE);

コンストラクタは、指定のTypeCode擬似オブジェクト参照を複製します。releaseパラメータがTRUEの場合、Anyオブジェクトは、valueパラメータが指すストレージの所有権を想定します。 せん。valueパラメータがrelease=TRUEの指定でAnyに対して処理された後は、呼出し側はこのパラメータの存続期間を想定できません。これは、Anyがvalueパラメータをコピーして、直ちに元のポインタを解放するためです。releaseパラメータがデフォルトのFALSEの場合、Anyオブジェクトは、valueによって指されるメモリーを呼出し側が管理すると想定します。valueパラメータはNULLポインタでもかまいません。

Anyクラスでは、3つの危険なオペレーションも定義します。

// C++
void replace(
TypeCode_ptr,
void *value,
Boolean release = FALSE
);
TypeCode_ptr type() const;
const void *value() const;

replace関数は、型保障挿入インタフェースで使用不可能な型で使用します。したがって、この関数は上述のコンストラクタに似ています。既存のTypeCodeは解放され、必要に応じて値のストレージの割当てが解除されます。TypeCode関数のパラメータは複製されます。releaseパラメータがTRUEの場合、Anyオブジェクトは、valueパラメータが指すストレージの所有権を想定します。valueパラメータがrelease=TRUEの指定でAny::replace関数に対して処理された後は、Anyはこのパラメータの存続期間を想定できません。これは、Anyがvalueパラメータをコピーして、直ちに元のポインタを解放するためです。releaseパラメータがデフォルトのFALSEの場合、Anyオブジェクトは、値が入っているメモリーを呼出し側が管理すると想定します。replace関数のvalueパラメータはNULLポインタでもかまいません。

上記のコンストラクタもreplace関数も型保障ではありません。特に、TypeCodeとvoid*引数の実際の型との一貫性については、実行時にコンパイラは保証しません。一致しないTypeCodeと値でAnyが作成される場合の、ORB実装の動作は定義されません。

type関数は、Anyに関連付けられたTypeCodeにTypeCode_ptr擬似オブジェクト参照を返します。すべてのオブジェクト参照の戻り値と同様に、リファレンスが不要になったときに呼出し側は、それを解放するか、または自動管理を行うためにTypeCode_var変数を割り当てる必要があります。

value関数は、Anyに格納されているデータへのポインタを返します。Anyに関連付けられている値がない場合、value関数はNULLポインタを返します。

Anyのコンストラクタ、デストラクタ、代入演算子

デフォルト・コンストラクタは、値を作成せずに、型tk_nullのTypeCodeでAnyを作成します。コピー・コンストラクタは、AnyパラメータのTypeCode_ptr_duplicateを呼び出し、パラメータの値をディープ・コピーします。代入演算子は、それ自身のTypeCode_ptrを解放し、必要に応じて現在の値のストレージを割当て解除します。その後、AnyパラメータのTypeCode_ptrを複製し、パラメータの値をディープ・コピーします。デストラクタは、TypeCode_ptrreleaseを呼び出し、必要に応じて値のストレージを割当て解除します。

その他のコンストラクタについては、「型付けされていない値の処理」を参照してください。

Anyクラス

Anyクラスの定義の詳細は、「Anyクラスのメンバー関数」を参照してください。

値型

このセクションは、Object Management Group (OMG)の「Common Object Request Broker: Architecture and Specification, Revision 2.4.2」(2001年2月)の第3章、第5章、および第6章、および「CORBA C++ Language Mapping Specification」(1999年6月)に記載されている情報に基づいています。使用にあたってはOMGの権限を得ています。

概要

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

値でオブジェクトを渡すセマンティクスは、標準のプログラミング言語のセマンティクスとほぼ同じです。値で渡されるパラメータの受信側は、オブジェクトの「状態」の記述を受信します。次に、受信側は新しいインタンスをその状態でインスタンス化します。その際、送信側のインスタンスのIDを個別に付けます。パラメータ渡しのオペレーションが完了すると、2つのインスタンス間には何の関係もないものと見なされます。

受信側はインスタンスをインスタンス化する必要があるため、オブジェクトの状態と実装に関する情報を認識している必要があります。そこで、値型では、CORBA構造体とCORBAインタフェースをブリッジする、次のセマンティクスを備えています。

アーキテクチャ

値型の基本概念は比較的単純です。ある意味で値型は、「通常の」IDLインタフェース型と構造体との中間的なものと言えます。アプリケーションのプログラマは、インタフェース型に関係なく追加のプロパティ(状態)と実装の詳細が指定されることを、値型を使用して通知します。この情報の指定は、インタフェース型に関係なく実装上の制約として追加されます。これは、ここで指定したセマンティクスと言語マッピングの両方に反映されます。

利点

値型(値で渡すことが可能なオブジェクト)のサポート以前は、CORBAオブジェクトには、すべてオブジェクト参照がありました。そのため、複数のクライアントが特定のオブジェクトを呼び出すとき、クライアントは同じリファレンスを使用していました。オブジェクトのインスタンスはサーバーORB上に残り、その状態はクライアントORBではなく、サーバーORBが管理していました。

値型は、CORBAアーキテクチャへの重要な追加機能であると言えます。参照によって受け渡されるオブジェクトに関して、値型には状態とメソッドが含まれますがオブジェクト参照は含まれず、プログラミング言語オブジェクトとして常にローカルで呼び出されます。受信側からのリクエスト時に、値型は送信側のコンテキストの状態をパッケージ化し、「over the wire」状態を受信側に送信します。受信側では、インスタンスが作成され、送信された状態が自動的に設定されます。この段階以降、送信側はクライアント側のインスタンスを制御できなくなります。つまり、これ以降は、受信側がインスタンスをローカルで呼び出すことができるようになります。このモデルにより、ネットワーク経由の通信で生じる遅延を短縮することができます。この遅延は、大規模なネットワークで顕著に生じます。値型を追加することにより、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;
};
The C++ mapping for this valuetype is:
// C++
class Example : public virtual ValueBase {
public:
virtual Short op1() = 0;
virtual Long op2(Example*) = 0;
      virtual Long val2() const = 0;
virtual void val2(Long) = 0;
      static Example* _downcast(ValueBase*);
   protected:
Example();
virtual ~Example();
      virtual Short val1() const = 0;
virtual void val1(Short) = 0;
      virtual const char* val3() const = 0;
virtual void val3(char*) = 0;
virtual void val3(const char*) = 0;
virtual void val3(const String_var&) = 0;
      virtual Float val4() const = 0;
virtual void val4(Float) = 0;
      virtual Example* val5() const = 0;
virtual void val5(Example*) = 0;
   private:
// private and unimplemented
void operator=(const Example&);
};
class OBV_Example : public virtual Example {
public:
virtual Long val2() const;
virtual void val2(Long);
   protected:
OBV_Example();
OBV_Example(Short init_val1, Long init_val2,
const char* init_val3, Float init_val4,
Example* init_val5);
virtual ~OBV_Example();
      virtual Short val1() const;
virtual void val1(Short);
      virtual const char* val3() const;
virtual void val3(char*);
virtual void val3(const char*);
virtual void val3(const String_var&);
      virtual Float val4() const;
virtual void val4(Float);
      virtual Example* val5() const;
virtual void val5(Example*);
      // ...
};

 


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

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

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

 


varクラスの使い方

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

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

varクラスのメンバー関数は共通ですが、OMG IDLの型によって演算子を追加でサポートする場合があります。OMG IDLの型TYPEの場合、TYPE_varクラスは、コンストラクタ、デストラクタ、代入演算子、および基底のTYPE型にアクセスするための演算子を格納しています。次に、varクラスの例を示します。

class TYPE_var
{
public:
// constructors
TYPE_var();
TYPE_var(TYPE *);
TYPE_var(const TYPE_var &);
// destructor
~TYPE_var();

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

// accessor operators
TYPE *operator->();
TYPE *operator->() const;
        TYPE_var_ptr in() const; 
TYPE_var_ptr& inout();
TYPE_var_ptr& out();
        TYPE_var_ptr _retn();
operator const TYPE_ptr&() const;
operator TYPE_ptr&();
operator TYPE_ptr;
};

次に、各メンバー関数の詳細について説明します。

TYPE_var()

TYPE_varクラスのデフォルトのコンストラクタです。このコンストラクタは0 (ゼロ)に初期化します。この値は、varクラスがTYPE *を所有することを示します。有効なTYPE *を割り当てていない限り、TYPE_varクラスでoperator->を呼び出すことはできません。

TYPE_var(TYPE * Value);

このコンストラクタは、指定のTYPE *パラメータの所有権を想定します。TYPE_varが破棄されると、TYPEは解放されます。Value引数は、このvarクラスが所有するTYPEへのポインタです。このポインタは0 (ゼロ)に指定しないでください。

TYPE_var(const TYPE_var & From);

このコピー・コンストラクタは、新しいTYPEを割り当てて、Fromパラメータが所有するTYPEに格納されているデータをディープ・コピーします。TYPE_varが破棄されると、TYPEのコピーは解放または削除されます。Fromパラメータには、コピー元のTYPEを指すvarクラスを指定します。

~TYPE_var();

このデストラクタは、varクラスが所有するTYPEを適切なメカニズムで解放します。文字列の場合は、CORBA::string_freeルーチンです。その他の参照の場合は、 CORBA::release ルーチンです。その他の型の場合はdelete、または割当て済みのメモリーを解放するために生成された静的ルーチンです。

TYPE_var &operator=(TYPE * NewValue);

この代入演算子は、NewValueパラメータが指すTYPEの所有権を想定します。現在、TYPE_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-5で示すように、代入演算子はすべてのデータ型でサポートされるので、比較には含まれていません。

表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_;
     // assignment from TYPE_var not allowed
void operator=(const TYPE_var&):
};

最初のコンストラクタは、リファレンス・データ・メンバーをT*&引数にバインドし、ポインタをゼロ(0)ポインタ値に設定します。2番目のコンストラクタは、リファレンス・データ・メンバーをTYPE_var引数が保持するポインタにバインドし、ポインタに対してdeleteを呼び出します(その際、型がString_outの場合はstring_free()を、配列型TYPETYPE_varの場合はTYPE_free()を呼び出します)。3番目のコンストラクタはコピー・コンストラクタで、コンストラクタ引数のデータ・メンバーによって参照される同じポインタにリファレンス・データ・メンバーをバインドします。

ほかのTYPE_outから代入すると、TYPE_out引数によって参照されるTYPE*がデータ・メンバーにコピーされます。TYPE*のオーバーロードの代入演算子は、ポインタ引数をデータ・メンバーに代入するだけです。この意味で、TYPE_out型の動作は、TYPE*とまったく同じです。TYPE*&変換演算子は、データ・メンバーを返します。ptr()メンバー関数もデータ・メンバーを返しますが、暗黙的な変換の実行を避ける場合に使用できます。オーバーロードの矢印演算子(operator->())を使用すると、TYPE*データ・メンバーが指すデータ構造体のメンバーにアクセスできます。準拠アプリケーションでは、有効な非NULL TYPE*TYPE_outが初期化済みでない限り、オーバーロードのoperator->()を呼び出すことはできません。

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

// C++
TYPE_var t = ...;
my_out = new
TYPE(t.in()); // heap-allocate a copy

通常、tに対して呼び出されるin()関数は、const TYPE&を戻して、新しく割り当てられたTインスタンスのコピー・コンストラクタを呼び出すことができるようにします。

また、TYPE_varで、T_outパラメータで返されるよう、それが管理するポインタの所有権を返すには、アプリケーションで、次のようにTYPE_var::_retn()関数を使用する必要があります。

// C++
TYPE_var t = ...;
my_out = t._retn(); // t yields ownership, no copy

TYPE_out型は、アプリケーションで作成または破棄される汎用目的のデータ型としては機能しません。この型は必要なメモリー管理を適切に行う目的で、オペレーションのシグネチャの内部でのみ使用する型です。

オブジェクト参照のoutパラメータ

_varoutパラメータとして渡すと、参照先の前の値はすべて暗黙的に解放する必要があります。この要件を満たす上でC++マッピング実装に十分なフックを付与するために、オブジェクト参照型ごとに_out型が生成されます。この型は、outパラメータ型としてのみ使用します。たとえば、インタフェースTYPEの場合、オブジェクト参照型TYPE_ptr、ヘルパー型TYPE_var、およびoutパラメータ型TYPE_outが生成されます。オブジェクト参照_out型の全般的な形式は次のとおりです。

// C++
class
TYPE_out
{
public:
TYPE_out(TYPE_ptr& p) : ptr_(p) { ptr_ = TYPE::_nil(); }
TYPE_out(TYPE_var& p) : ptr_(p.ptr_) {
release(ptr_); ptr_ =
TYPE::_nil();
}
TYPE_out(TYPE_out& a) : ptr_(a.ptr_) {}
TYPE_out& operator=(TYPE_out& a) {
ptr_ = a.ptr_; return *this;
}
TYPE_out& operator=(const TYPE_var& a) {
ptr_ =
TYPE::_duplicate(TYPE_ptr(a)); return *this;
}
TYPE_out& operator=(TYPE_ptr p) { ptr_ = p; return *this; }
operator
TYPE_ptr&() { return ptr_; }
TYPE_ptr& ptr() { return ptr_; }
TYPE_ptr operator->() { return ptr_; }

private:
TYPE_ptr& ptr_;
};

シーケンスout

シーケンスoutでは、次のoperator[]メンバー関数を追加でサポートします。

TYPE &operator[](CORBA::ULong Index);

この演算子は、outクラスが所有するシーケンスのoperator[]を呼び出します。operator[]は、指定の索引でシーケンスの適切な要素へのリファレンスを返します。Index引数には、戻り値となる要素の索引を指定します。この索引は、現在のシーケンスの長さを超えることはできません。

配列out

配列outでは、配列要素にアクセスするためにoperator->ではなく、次のoperator[]メンバー関数を追加でサポートします。

TYPE_slice& operator[](CORBA::ULong Index);
const TYPE_slice & operator[](CORBA::ULong Index) const;

上記の演算子は、指定の索引で配列スライスへのリファレンスを返します。配列のスライスとは、元の配列の最初のサイズを除いたすべてのサイズを持つ配列のことです。配列で生成されたクラスのメンバー関数は、スライスへのポインタを使用して配列へのポインタを返します。Index引数には、戻り値となるスライスの索引を指定します。この索引は、配列のサイズを超えることはできません。

文字列out

String_varoutパラメータとして渡すと、参照先の前の値はすべて暗黙的に解放する必要があります。この要件を満たす上でC++マッピング実装に十分なフックを付与するために、文字列型にもCORBAネームスペースでString_out型が生成されます。この型は、文字列outパラメータ型としてのみ使用します。String_out型の全般的な形式は次のとおりです。

// C++
class String_out
{
public:
String_out(char*& p) : ptr_(p) { ptr_ = 0; }
String_out(String_var& p) : ptr_(p.ptr_) {
string_free(ptr_); ptr_ = 0;
}
String_out(String_out& s) : ptr_(s.ptr_) {}
String_out& operator=(String_out& s) {
ptr_ = s.ptr_; return *this;
}
String_out& operator=(char* p) {
ptr_ = p; return *this;
}
String_out& operator=(const char* p) {
ptr_ = string_dup(p); return *this;
}
operator char*&() { return ptr_; }
char*& ptr() { return ptr_; }
  private:
char*& ptr_;
     // assignment from String_var disallowed
void operator=(const String_var&);
};

最初のコンストラクタは、リファレンス・データ・メンバーをchar*&引数にバインドします。2番目のコンストラクタは、リファレンス・データ・メンバーをString_var引数が保持するchar*にバインドし、文字列に対してstring_free()を呼び出します。3番目のコンストラクタはコピー・コンストラクタで、その引数のデータ・メンバーにバインドされる同じchar*に、リファレンス・データ・メンバーをバインドします。

ほかのString_outから代入すると、String_out引数によって参照されるchar*が、データ・メンバーによって参照されるchar*にコピーされます。char*のオーバーロードの代入演算子は、char*引数をデータ・メンバーに代入するだけです。const char*のオーバーロードの代入演算子は、引数を複製して結果をデータ・メンバーに代入します。代入を行っても、以前に保持されていた文字列はまったく削除されません。この意味で、String_out型の動作は、char*とまったく同じです。char*&変換演算子は、データ・メンバーを返します。ptr()メンバー関数もデータ・メンバーを返しますが、暗黙的な変換の実行を避ける場合に使用できます。

String_varからString_outへの代入はできません。これは、メモリー管理にあいまいさが生じるためです。特に、String_varによって所有される文字列をString_outが取得するときに、コピーが行われるか、コピーなしで行われるかどうかを判別することは不可能です。String_varからの代入が不可能なため、アプリケーション開発者は次のように明示的に指定しなければなりません。

// C++
void
A::op(String_out arg)
{
String_var s = string_dup("some string");
...
out = s; // disallowed; either
out = string_dup(s); // 1: copy, or
out = s._retn(); // 2: adopt
}

コメントで「1」とマークされた行の場合、呼出し側はString_varが所有する文字列を明示的にコピーし、結果をout引数に代入しています。また、呼出し側は、コメントで「2」とマークされた行で示すように、String_varに文字列の所有権を強制的に放棄させるというテクニックも使用できます。これにより、メモリー管理のエラーを発生させずにout引数に文字列を返すことができます。

 


引数の受け渡しの考慮事項

パラメータ渡しモードのマッピングでは、効率性と簡便性の両方のバランスを調整します。プリミティブ型、列挙、およびオブジェクト参照の場合、モードは単純で、プリミティブと列挙用の型P、およびインタフェース型A用の型A_ptrを渡します。

集約型は複雑です。これは、いつ、どのようにパラメータのメモリーを割り当てるか、または割当て解除するかという問題があるためです。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);
// use s
f(s); // first result will be freed

S *sp; // need not initialize before passing to out
f(sp);
// use sp
delete sp; // cannot assume next call will free old value
f(sp);

outパラメータとinoutパラメータの前の値を暗黙的に割当て解除できるのは、T_var型だけです。

// IDL
void q(out string s);
// C++
char *s;
for (int i = 0; i < 10; i++)
q(s); // memory leak!

ループ内でq関数を呼び出すたびに、メモリー・リークが発生します。これは、呼出し側がout結果でstring_freeを呼び出していないことが原因です。これを修正するには、次に示す2つの方法があります。

// C++
char *s;
String_var svar;
for (int i = 0 ; i < 10; i++) {
q(s);
string_free(s); // explicit deallocation
// OR:
q(svar); // implicit deallocation
}

outパラメータに通常のchar*を使用する場合、呼出し側は変数を毎回outパラメータとして再利用する前に、明示的にメモリーを割当て解除する必要があります。一方、String_varを使用した場合は、変数をoutパラメータとして使用するたびに、割当てがすべて暗黙的に解除されます。

可変長データは、上書きされる前に明示的に解放しなければなりません。たとえば、inout文字列パラメータへの割当ての前に、オペレーションの実装者は最初に古い文字データから削除します。同様に、inoutインタフェース・パラメータは、再割り当てされる前に解放する必要があります。パラメータのストレージを確実に解放する方法としては、次の例に示すように、ストレージをローカルT_var変数に割り当てて自動的に解放が行われるようにすることです。

// IDL
interface A;
void f(inout string s, inout A obj);
// C++
void Aimpl::f(char *&s, A_ptr &obj) {
String_var s_tmp = s;
s = /* new data */;
A_var obj_tmp = obj;
obj = /* new reference */
}

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

ただし、呼出し側は、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


  先頭に戻る       前  次