![]() |
![]() |
BEA WebLogic Enterprise 4.2 Developer Center |
![]() HOME | SITE MAP | SEARCH | CONTACT | GLOSSARY | PDF FILES | WHAT'S NEW |
||
![]() C++ REFERENCE | TABLE OF CONTENTS | PREVIOUS TOPIC | NEXT TOPIC |
This chapter discusses the mappings from OMG IDL statements to C++.
Note:
Some of the information in this chapter is taken from the Common Object Request Broker: Architecture and Specification. Revision 2.2, February 1998, published by the Object Management Group (OMG). Used with permission by OMG.
OMG IDL-to-C++ mappings are described for the following:
Mappings
This chapter also describes the generated var classes for user-defined data types.
Each OMG IDL data type is mapped to a C++ data type or class.
The basic data types in OMG IDL statements are mapped to C++ typedefs in the CORBA module, as shown in Table 11-1.
Note:
On a 64-bit machine where a long integer is 64 bits, the definition of Object, pseudo-object, and user-defined types are mapped as shown in Table 11-2.
The mapping for strings and UDTs is described in more detail in the following sections.
A string in OMG IDL is mapped to If a string is contained within another user-defined type, such as a Strings must be allocated and deallocated using the following member functions in the CORBA class:
Data Types
Basic Data Types
CORBA::Long
would still refer to a 32-bit integer.
Complex Data Types
Strings
char *
in C++. Both bounded and unbounded strings are mapped to char *
. CORBA strings in C++ are NULL-terminated and can be used wherever a char * type is used.
struct
, it is mapped to a CORBA::String_var
type. This ensures that each member in the struct manages its own memory.
string_alloc
For more information about string member functions, see the section "Strings" on page 1-119 A constant in OMG IDL is mapped to a C++ This definition maps to C++ as follows:
Top-level constants are initialized in the generated The following is an example of a valid reference to the An enum in OMG IDL is mapped to an enum in C++. For example, consider the following OMG IDL definition:
This definition maps to C++ as follows:
The following is an example of a valid reference to the enum defined in the previous example. You refer to enum as follows:
A struct in OMG IDL is mapped to a C++ struct.
The generated code for a struct depends upon whether it is fixed-length or variable-length. For more information about fixed-length versus variable-length types, see the section "Fixed-Length Versus Variable-Length User-Defined Types" on page 11-49.
A variable-length struct contains an additional assignment operator member function to handle assignments between two variable-length structs.
For example, consider the following OMG IDL definition:
This definition maps to C++ as follows:
Members of a struct are mapped to the appropriate C++ data type. For basic data types (long, short, and so on), see Table 11-1 on page 11-2. For object references, pseudo-object references, and strings, the member is mapped to the appropriate var class:
Constants
const
definition. For example, consider the following OMG IDL definition:
// OMG IDL
const string CompanyName = "BEA Systems Incorporated";
module INVENT
{
const string Name = "Inventory Modules"; interface Order
{
const long MAX_ORDER_NUM = 10000;
};
}; // 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
include file, but module and interface constants are initialized in the generated client stub modules.
MAX_ORDER_NUM
constant, as defined in the previous example:
CORBA::Long accnt_id = INVENT::Order::MAX_ORDER_NUM;
Enums
// OMG IDL
module INVENT
{
enum Reply {ACCEPT, REFUSE};
} // C++
class INVENT
{
. . . enum Reply {ACCEPT, REFUSE};
}; INVENT::Reply accept_reply;
accept_reply = INVENT::ACCEPT; Structs
Fixed-Length Versus Variable-Length Structs
// 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++
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);
};
}; Member Mapping
CORBA::String_var
All other data types are mapped as shown in Table 11-2, "Object, Pseudo-Object, and User-Defined OMG IDL and C++ Types," on page 11-3.
No constructor for a generated struct exists, so none of the members are initialized. Fixed-length structs can be initialized using aggregate initialization. For example:
Variable-length members map to self-managing types; these types have constructors that initialize the member.
A var class is generated for structs. For more information, see the section "Using var Classes" on page 11-50.
An out class is generated for structs. For more information, see the section "Using out Classes" on page 11-56.
A union in OMG IDL is mapped to a C++ class. The C++ class contains the following:
INVENT::Date a_date = { 1995, 10, 12 };
Var
Out
Unions
For example, consider the following OMG IDL definition:
This definition maps to C++ as follows:
The default union constructor does not set a default discriminator value for the union; therefore, you cannot call any union accessor member function until you have set the value of the union. The discriminator is an attribute that is mapped through the For each member in the union, accessor and modifier member functions are generated.
In the following code, taken from the previous example, two member functions are generated for the ID member function:
In this example, the first function (the modifier) sets the discriminator to the default value and sets the value of the union to the specified ID value. The second function, the accessor, returns the value of the union.
Depending upon the data type of the union member, additional modifier functions are generated. The member functions generated for each data type are as follows:
// OMG IDL
union OrderItem switch (long)
{
case 1: itemStruct itemInfo;
case 2: orderStruct orderInfo;
default: ID idInfo;
}; // 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
member function.
Union Member Accessor and Modifier Member Function Mapping
void idInfo (ID);
ID idInfo () const;
basictype
:void basictype (
TYPE
); // modifier
TYPE
basictype () const; // accessor
For object and Typecode types with member name objtype
, member functions are generated as follows:void objtype (
TYPE); // modifier
TYPE
objtype () const; // accessor
For the mapping from an OMG IDL data type to the C++ data type TYPE, see Table 11-1, "Basic OMG IDL and C++ Data Types," on page 11-2.
The modifier member function does not assume ownership of the specified object reference argument. Instead, the modifier duplicates the object reference or pseudo-object reference. You are responsible for releasing the reference when it is no longer required.
A var class is generated for a union. For more information, see the section "Using var Classes" on page 11-50 .
An out class is generated for a union. For more information, see the section "Using out Classes" on page 11-56.
In addition to the accessor and modifiers, the following member functions are generated for an OMG IDL union of type TYPE with switch (long) discriminator:
Var
Out
Member Functions
TYPE
();
TYPE
( const
TYPE
& From);
From
argument specifies the union to be copied.
~
TYPE
();
TYPE
&operator=(const
TYPE
& From);
From
argument specifies the union to be copied.
void _d (CORBA::Long Descrim);
Descrim
argument specifies the new discriminant. The data type of the argument is determined by the OMG IDL data type specified in the switch statement of the union. For each OMG IDL data type, see Table 11-1, "Basic OMG IDL and C++ Data Types," on page 11-2 for the C++ data type.
CORBA::Long _d () const;
A sequence in OMG IDL is mapped to a C++ class. The C++ class contains the following:
Each sequence has the following:
You must set the length before accessing any elements.
For example, consider the following OMG IDL definition:
This definition maps to C++ as follows:
The For basic data types, see Table 11-1, "Basic OMG IDL and C++ Data Types," on page 11-2. For object references, TypeCode references, and strings, the base type is mapped to a generated All other data types are mapped as shown in Table 11-2, "Object, Pseudo-Object, and User-Defined OMG IDL and C++ Types," on page 11-3.
A var class is generated for a sequence. For more information, see the section "Using var Classes" on page 11-50.
An out class is generated for a sequence. For more information, see the section "Using out Classes" on page 11-56.
For a given OMG IDL sequence SEQ with base type TYPE, the member functions for the generated sequence class are described as follows:
// OMG IDL
module INVENT
{
. . .
typedef sequence<LogItem> LogList;
}// 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 *);
}; };
Sequence Element Mapping
operator[]
functions are used to access or modify the sequence element. These operators return a reference to the sequence element. The OMG IDL sequence base type is mapped to the appropriate C++ data type.
_ForSeq_var
class. The _ForSeq_var
class provides the capability to update a string or an object that is stored within the sequence. This generated class has the same member functions and signatures as the corresponding var class. However, this _ForSeq_var
class honors the setting of the release parameter in the sequence constructor. The distinction is that the _ForSeq_var
class lets users specify the Release
flag, thereby allowing users to control the freeing of memory.
Vars
Out
Member Functions
SEQ ();
SEQ (CORBA::ULong Max);
Max
argument specifies the maximum length of the sequence.
SEQ (CORBA::ULong Max, CORBA::ULong Length,
TYPE
* Value,
CORBA::Boolean Release);
Release
flag determines whether elements are released when the sequence is destroyed. Explanations of the arguments are as follows:
Max
Length
Value
Release
CORBA_TRUE
, the sequence assumes ownership of the buffer pointed to by the Value
argument. If the Release
flag is CORBA_ TRUE
, this buffer must be allocated using the allocbuf
member function, because it will be freed using the freebuf
member function when the sequence is destroyed.
SEQ(const S& From);
From
argument specifies the sequence to be copied.
~SEQ();
Release
flag, may free the sequence elements.
SEQ& operator=(const SEQ& From);
Release
flag in the current sequence is set to CORBA_TRUE
. The From
argument specifies the sequence to be copied.
CORBA::ULong maximum( ) const;
void length(CORBA::ULong Length);
Length
argument specifies the new length of the sequence. If the sequence is unbounded and the new length is greater than the current maximum, the buffer is reallocated and the elements are copied to the new buffer. If the new length is greater than the maximum, the maximum is set to the new length.
For a bounded sequence, the length cannot be set to a value greater than the maximum.
CORBA::ULong length() const;
TYPE
& operator[](CORBA::ULong Index);
const
TYPE
& operator[](CORBA::ULong Index) const;
Index
argument specifies the index of the element to return. This index cannot be greater than the current sequence length. The length must have been set either using the TYPE * constructor or the length(CORBA::ULong)
modifier. If TYPE is an object reference, TypeCode reference, or string, the return type will be a ForSeq_var
class.
static
TYPE
* allocbuf(CORBA::ULong NumElems);
TYPE
*
constructor. The NumElems argument specifies the number of elements in the buffer to allocate. If the buffer cannot be allocated, NULL is returned.
If this buffer is not passed to the TYPE
*
constructor with release set to CORBA_TRUE
, it should be freed using the freebuf
member function.
static void freebuf(
TYPE
* Value);
TYPE
*
sequence buffer allocated by the allocbuf
function. The Value
argument specifies the TYPE
*
buffer allocated by the allocbuf
function. A 0 (zero) pointer is ignored.
An array in OMG IDL is mapped to a C++ array definition. For example, consider the following OMG IDL definition:
// OMG IDL
module INVENT
{
. . .
typedef LogItem LogArray[10];
};
This definition maps to C++ as follows:
// C++
module INVENT
{
. . .
typedef LogItem LogArray[10];
typedef LogItem LogArray_slice;
static LogArray_slice * LogArray_alloc(void);
static void LogArray_free(LogArray_slice *data);
};
A slice of an array is an array with all the dimensions of the original array except the first demension. The member functions for the array-generated classes use a pointer to a slice to return pointers to an array. A typedef for each slice is generated.
For example, consider the following OMG IDL definition:
// OMG IDL
typedef LogItem LogMultiArray[5][10];
This definition maps to C++ as follows:
// C++
typedef LogItem LogMultiArray[5][10];
typedef LogItem LogMultiArray_slice[10];
If you have a one-dimensional array, an array slice is just a type. For example, if you had a one-dimensional array of long
, an array slice would result in a CORBA::Long
data type.
The type of the OMG IDL array is mapped to the C++ array element type in the same manner as structs. For more information, see the section "Member Mapping" on page 11-8.
A var class is generated for an array. For more information, see the section "Using var Classes" on page 11-50.
An out class is generated for an array. For more information, see the section "Using out Classes" on page 11-56.
For each array, there are two static functions for array allocation and deallocation. For a given OMG IDL type TYPE
, the allocation and deallocation routines are as follows:
static
TYPE
_slice *
TYPE
_alloc(void);
TYPE
array, returning a pointer to the allocated TYPE
array. If the array cannot be dynamically allocated, 0 (zero) is returned.
static void
TYPE
_free(
TYPE
_slice * Value);
TYPE
array. The Value
argument is a pointer to the dynamically allocated TYPE
array to be freed.
An exception in OMG IDL is mapped to a C++ class. The C++ class contains the following:
The generated class is similar to a variable-length structure, but with an additional constructor to simplify initialization, and with the static For example, consider the following OMG IDL definition:
This definition maps to C++ as follows:
Attributes (data members) of the Exception class are public, so you may access them directly.
Members of an exception are mapped in the same manner as structs. For more information, see "Member Mapping" on page 11-8.
All exception members are public data in the C++ class, and are accessed directly.
A var class is generated for an exception. For more information, see the section "Using var Classes" on page 11-50.
An out class is generated for an exception. For more information, see the section"Using out Classes" on page 11-56.
For a given OMG IDL exception _narrow
member function to determine the type of UserException.
// OMG IDL
module INVENT
{
exception NonExist
{
ID BadId;
};
}; // 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;
};
}; Member Mapping
Var
Out
Member Functions
TYPE
, the generated member functions are as follows:
static
TYPE
* _narrow(CORBA::Exception_ptr Except);
TYPE
exception class if the exception can be narrowed to a TYPE
exception. If the exception cannot be narrowed, 0 (zero) is returned. The TYPE
pointer is not a pointer to a new class. Instead, it is a typed pointer to the original exception pointer and is valid only as long as the Except parameter is valid.
TYPE
( );
TYPE
(member-parameters);
NonExist (ID _BadId);
TYPE
(const
TYPE
& From);
TYPE
exception argument. The From
argument specifies the exception to be copied.
~
TYPE
();
TYPE
& operator=(const
TYPE
& From);
TYPE
exception argument. The From
argument specifies the exception to be copied.
void _raise ();
CORBA pseudo-objects may be implemented either as normal CORBA objects or as serverless objects. In the CORBA specification, the fundamental differences between these strategies are:
CORBA::Object
.
References to serverless objects are not necessarily valid across computational contexts; for example, address spaces. Instead, references to serverless objects that are passed as parameters may result in the construction of independent, functionally identical copies of objects used by receivers of these references. To support this, the otherwise hidden representational properties (such as data layout) of serverless objects are made known to the ORB. Specifications for achieving this are not contained in this chapter; making serverless objects known to the ORB is an implementation detail.
This chapter provides a standard mapping algorithm for all pseudo-object types. This avoids the need for piecemeal mappings for each of the nine CORBA pseudo-object types, and accommodates any pseudo-object types that may be proposed in future revisions of CORBA. It also avoids representation dependence in the C mapping, while still allowing implementations that rely on C-compatible representations.
Rather than C-PIDL, this mapping uses an augmented form of full OMG IDL to describe serverless object types. Interfaces for pseudo-object types follow the same rules as normal OMG IDL interfaces, with the following exceptions:
Usage
pseudo
.
The Serverless objects are mapped in the same way as normal interfaces, except for the differences outlined in this section.
Classes representing serverless object types are not subclasses of For each class representing a serverless object type The mapped C++ classes are not guaranteed to be usefully subclassable by users, although subclasses can be provided by implementations. Implementations are allowed to make assumptions about internal representations and transport formats that may not apply to subclasses.
The member functions of classes representing serverless object types do not necessarily obey the normal memory management rules. This is because some serverless objects, such as All other elements of the mapping are the same. In particular:
pseudo
prefix means that the interface may be implemented in either a normal or serverless fashion. That is, apply either the rules described in the following sections, or the normal mapping rules described in this chapter.
Mapping Rules
CORBA::Object
, and are not necessarily subclasses of any other C++ class. Thus, they do not necessarily support, for example, the Object::create_request
operation.
T
, overloaded versions of the following functions are provided in the CORBA namespace:
// C++
void release(T_ptr);
Boolean is_nil(T_ptr p);CORBA::NVList
, are essentially just containers for several levels of other serverless objects. Requiring callers to explicitly free the values returned from accessor functions for the contained serverless objects would be counter to their intended usage.
T_ptr
, may or may not simply be a typedef of T*
.
// C++
static T_ptr _duplicate(T_ptr p);
static T_ptr _nil();
All serverless object interfaces and declarations that rely on them have direct analogs in the C mapping. The mapped C++ classes can, but need not, be implemented using representations compatible to those chosen for the C mapping. Differences between the pseudo-object specifications for C-PIDL and C++ PIDL are as follows:
Relation to the C PIDL Mapping
Brief descriptions and listings of each pseudo-interface and its C++ mapping are provided in the following sections. Further details, including definitions of types referenced but not defined below, may be found in the relevant sections of this document.
A typedef in OMG IDL is mapped to a typedef in C++. Depending upon the OMG IDL data type, additional typedefs and member functions may be defined. The generated code for each data type is as follows:
Typedefs
Basic data types map to a simple typedef. For example:
// OMG IDL
typedef long ID;// C++
typedef CORBA::Long ID;
A string typedef is mapped to a simple typedef. For example:
// OMG IDL
typedef string IDStr;// C++
typedef char * IDStr;
Object, interfaces, and TypeCode types are mapped to four typedefs. For example:
// OMG IDL
typedef Item Intf;// C++
typedef Item Intf;
typedef Item_ptr Intf_ptr;
typedef Item_var Intf_var;
typedef Item_ptr & Intf _out;
UDTs are mapped to three typedefs. For example:
// OMG IDL
typedef LogList ListRetType;// C++
typedef LogList ListRetType;
typedef LogList_var ListRetType_var;
typedef LogList_out & ListRetType_out;
Arrays are mapped to four typedefs and the static member functions to allocate and free memory. For example:
// OMG IDL
typedef LogArray ArrayRetType;// C++
typedef LogArray ArrayRetType;
typedef LogArray_var ArrayRetType_var;
typedef LogArray_forany ArrayRetType_forany;
typedef LogArray_slice ArrayRetType_slice;
ArrayRetType_slice * ArrayRetType_alloc();
void ArrayRetType_free(ArrayRetType_slice *);
An operation in OMG IDL is mapped to a C++ member function.
The name of the member function is the name of the operation. The operation is defined as a member function in both the interface class and the stub class. The interface class is virtual; the stub class inherits from the virtual class and contains the member function code from the client application stub. When an operation is invoked on the object reference, the code contained in the corresponding stub member function executes.
For example, consider the following OMG IDL definition:
This definition maps to C++ as follows:
The generated client application stub then contains the following generated code for the stub class:
Each of the arguments in an operation is mapped to the corresponding C++ type as described in Table 11-1, "Basic OMG IDL and C++ Data Types," on page 11-2 and Table 11-2, "Object, Pseudo-Object, and User-Defined OMG IDL and C++ Types," on page 11-3.
The parameter passing modes for arguments in an operation are described in Table 11-7, "Basic Argument and Result Passing," on page 11-65 and Table 11-8, "T_var Argument and Result Passing," on page 11-66.
The signature of an implementation member function is the mapped signature of the OMG IDL operation. Unlike the client side, the server-side mapping requires that the function header include the appropriate exception ( Since all operations and attributes may throw CORBA system exceptions, Within a member function, the "this" pointer refers to the implementation object's data as defined by the class. In addition to accessing the data, a member function may implicitly call another member function defined by the same class. For example:
However, when a servant member function is invoked in this manner, it is being called simply as a C++ member function, not as the implementation of an operation on a CORBA object. In such a context, any information available via the In several existing ORB implementations, each skeleton class derives from the corresponding interface class. For example, for interface Such code can be supported by a conforming ORB implementation, but it is not required, and is thus not portable. The equivalent portable code invokes Objects registered with POAs use sequences of octet, specifically the These functions follow the normal C++ mapping rules for parameter passing and memory management.
If conversion of an A module in OMG IDL is mapped to a C++ class. Objects contained in the module are defined within this C++ class. Because interfaces and types are also mapped to classes, nested C++ classes result.
For example, consider the following OMG IDL definition:
This definition maps to C++ as follows:
Multiple nested modules yield multiple nested classes. Anything inside the module will be in the module class. Anything inside the interface will be in the interface class.
OMG IDL allows modules, interfaces, and types to have the same name. However, when generating files for the C++ language, having the same name is not allowed. This restriction is necessary because the OMG IDL names are generated into nested C++ classes with the same name; this is not supported by C++ compilers.
Note:
The WLE OMG IDL compiler outputs an informational message if you generate C++ code from OMG IDL with an interface or type with the same name as the current module name. If you ignore this informational message and do not use unique names to differentiate the interface or type from the module name, the compiler will signal errors when compiling the generated files.
An interface in OMG IDL is mapped to a C++ class. This class contains the definitions of the operations, attributes, constants, and user-defined types (UDTs) contained in the OMG IDL interface.
For an interface INTF, the generated interface code contains the following items:
Implementing Interfaces
// OMG IDL
module INVENT
{
interface Order
{
. . .
ItemList modifyOrder (in ItemList ModifyList);
};
};// 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)
{
. . .
} Argument Mapping
Implementing Operations
throw
) specification. This requirement allows the compiler to detect when an invalid exception is raised, which is necessary in the case of a local C++-to-C++ library call (otherwise, the call would have to go through a wrapper that checks for a valid exception). For example:
// 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::SystemException
must appear in all exception specifications, even when an operation has no raises
clause.
// 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();
}POA_Current
object refers to the CORBA request invocation that performed the C++ member function invocation, not to the member function invocation itself.
Skeleton Derivation from Object
Mod::A
, the skeleton class POA_Mod::A
is derived from class Mod::A
. These systems, therefore, allow an object reference for a servant to be implicitly obtained via normal C++ derived-to-base conversion rules:
// C++
MyImplOfA my_a; // declare impl of A
A_ptr a = &my_a; // obtain its object reference
// by C++ derived-to-base conversion_this()
on the implementation object to implicitly register it if it has not yet been registered, and to get its object reference:
// C++
MyImplOfA my_a; // declare impl of A
A_ptr a = my_a._this(); // obtain its object reference PortableServer Functions
PortableServer::POA::ObjectId
type, as object identifiers. However, because C++ programmers often want to use strings as object identifiers, the C++ mapping provides several conversion functions that convert strings to ObjectId
and vice versa:
// C++
namespace PortableServer
{
char* ObjectId_to_string(const ObjectId&);
ObjectId* string_to_ObjectId(const char*);
}ObjectId
to a string would result in illegal characters in the string (such as a NUL), the first two functions throw the CORBA::BAD_PARAM
exception.
Modules
// OMG IDL
module INVENT
{
interface Order
{
. . .
};
}; // C++
class INVENT
{
. . .
class Order : public virtual CORBA::Object
{
. . .
}; // class Order
}; // class INVENT Interfaces
_var
)
_duplicate
static member function
For example, consider the following OMG IDL definition:
This definition maps to C++ as follows:
The object reference types and static member functions are described in the following sections, as are UDTs, operations, and attributes.
This section describes in detail the generated static member functions: // OMG IDL
module INVENT
{
interface Order
{
void cancelOrder ();
};
}; // 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;
. . .
};
}; Generated Static Member Functions
_duplicate, _narrow,
and _nil
for an interface INTF.
static
INTF
_ptr _duplicate (
INTF
_ptr Obj)
CORBA::release
member function. If an error occurs, a reference to the nil INTF object is returned. The argument Obj
specifies the object reference to be duplicated.
static
INTF
_ptr _narrow (CORBA::Object_ptr Obj)
CORBA::Object_ptr
object reference. The Object_ptr
object reference may have been created by a call to the CORBA::ORB::string_to_object
member function or may have been returned as a parameter from an operation.
The INTF
_ptr
object reference must correspond to an INTF object or to an object that inherits from the INTF object. The new INTF object reference must be released by calling the CORBA::release member
function. The argument Obj
specifies the object reference to be narrowed to an INTF object reference. The Obj
parameter is not modified by this member function and should be released by the user when it is no longer required. If Obj
cannot be narrowed to an INTF object reference, the INTF nil object reference is returned.
static
INTF
_ptr _nil ( )
INTF interface. The new reference does not have to be released by calling the CORBA::release
member function.
An interface class (INTF) is a virtual class; the CORBA standard does not allow you to:
Instead, you use one of the object reference types, The A read-only attribute in OMG IDL is mapped to a C++ function that returns the attribute value. A read-write attribute maps to two overloaded C++ functions, one to return the attribute value and one to set the attribute value. The name of the overloaded member function is the name of the attribute.
Attributes are generated in the same way that operations are generated. They are defined in both the virtual and the stub classes. For example, consider the following OMG IDL definition:
This definition maps to C++ as follows:
The generated client application stub then contains the following generated code for the stub class:
An attribute is equivalent to two operations, one to return the attribute and one to set the attribute. For example, the The argument mapping for the attribute is the same as the mapping for an operation argument. The attribute is mapped to the corresponding C++ type as described in Table 11-1, "Basic OMG IDL and C++ Data Types," on page 11-2 and Table 11-2, "Object, Pseudo-Object, and User-Defined OMG IDL and C++ Types," on page 11-3. The parameter passing modes for arguments in an operation are described in Table 11-7, "Basic Argument and Result Passing," on page 11-65 and Table 11-8, "T_var Argument and Result Passing," on page 11-66.
An To decrease the chances of creating an Since the type-safe
INTF
_ ptr
or INTF
_var
class.
You can obtain an object reference by using the _narrow
static member function. Operations are invoked on these classes using the arrow operator (->
).
INTF
_var
class simplifies memory management by automatically releasing the object reference when the INTF
_var
class goes out of scope or is reassigned. Variable types are generated for many of the UDTs and are described in "Using var Classes" on page 11-50.
Attributes
// OMG IDL
module INVENT
{
interface Order
{
. . .
attribute itemStruct itemInfo;
};
};// 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)
{
} Argument Mapping
itemInfo
attribute listed above is equivalent to:
void itemInfo (in itemStruct itemInfo);
itemStruct itemInfo (); Any Type
any
in OMG IDL is mapped to the CORBA::Any
class. The CORBA::Any
class handles C++ types in a type-safe manner.
Handling Typed Values
any
with a mismatched TypeCode and value, the C++ function overloading facility is utilized. Specifically, for each distinct type in an OMG IDL specification, overloaded functions to insert and extract values of that type are provided. Overloaded operators are used for these functions to completely avoid any name space pollution. The nature of these functions, which are described in detail below, is that the appropriate TypeCode is implied by the C++ type of the value being inserted into or extracted from the any
.
any
interface described below is based upon C++ function overloading, it requires C++ types generated from OMG IDL specifications to be distinct. However, there are special cases in which this requirement is not met:
char*
regardless of whether they are bounded or unbounded, another means of creating or setting an any
with a bounded string value is necessary. This is described in "Distinguishing boolean, octet, char, and Bounded Strings" on page 11-44.
any
when dealing with arrays is described below and in "Arrays" on page 11-18.
To allow a value to be set in an any
in a type-safe fashion, the following overloaded operator function is provided for each separate OMG IDL type T:
// C++
void operator<<=(Any&, T);
This function signature suffices for the following types, which are usually passed by value:
Short
, UShort
, Long
, ULong
, Float
, Double
For values of type T that are too large to be passed by value efficiently, two forms of the insertion function are provided:
// C++
void operator<<=(Any&, const T&); // copying form
void operator<<=(Any&, T*); // non-copying form
Note that the copying form is largely equivalent to the first form shown, as far as the caller is concerned.
These "left-shift-assign" operators are used to insert a typed value into an any
, as follows:
// C++
Long value = 42;
Any a;
a <<= value;
In this case, the version of operator<<=
overloaded for type Long
sets both the value and the TypeCode properly for the Any variable.
Setting a value in an any
using operator<<=
means the following:
operator<<=
, the lifetime of the value in the Any is independent of the lifetime of the value passed to operator<<=
. The implementation of the Any does not store its value as a reference or a pointer to the value passed to operator<<=
.
operator<<=
, any previous value held by the Any
is properly deallocated. For example, if the Any(TypeCode_ptr,void*,TRUE)
constructor (described in "Handling Untyped Values" on page 11-47) were called to create the Any
, the Any
is responsible for deallocating the memory pointed to by the void*
before copying the new value.
Copying insertion of a string type causes the following function to be invoked:
// C++
void operator<<=(Any&, const char*);
Since all string types are mapped to char*
, this insertion function assumes that the value being inserted is an unbounded string. "Distinguishing boolean, octet, char, and Bounded Strings" on page 11-44 describes how bounded strings may be correctly inserted into an Any
. Noncopying insertion of both bounded and unbounded strings can be achieved using the Any::from_string
helper type described in "Distinguishing boolean, octet, char, and Bounded Strings" on page 11-44.
Type-safe insertion of arrays uses the Array_forany
types described in "Arrays" on page 11-18. The ORB provides a version of operator<<=
overloaded for each Array_forany
type. For example:
// 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 &);
The Array_forany
types are always passed to operator<<=
by reference to const
. The nocopy
flag in the Array_forany
constructor is used to control whether the inserted value is copied (nocopy == FALSE
) or consumed (nocopy == TRUE
). Because the nocopy
flag defaults to FALSE
, copying insertion is the default.
Because of the type ambiguity between an array of T
and a T*
, it is highly recommended that portable code explicitly use the appropriate Array_forany
type when inserting an array into an Any. For example:
// 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
Line 1 results in the invocation of the noncopying operator<<=(Any&, S*)
due to the decay of the SA
array type into a pointer to its first element, rather than the invocation of the copying SA_forany
insertion operator. Line 2 explicitly constructs the SA_forany
type and thus results in the desired insertion operator being invoked.
The noncopying version of operator<<=
for object references takes the address of the T_ptr
type, as follows:
// IDL
interface T { ... };
// C++
void operator<<=(Any&, T_ptr); // copying
void operator<<=(Any&, T_ptr*); // non-copying
The noncopying object reference insertion consumes the object reference pointed to by T_ptr*
; therefore, after insertion the caller may not access the object referred to by T_ptr
because the Any may have duplicated and then immediately released the original object reference. The caller maintains ownership of the storage for the T_ptr
itself.
The copying version of operator<<=
is also supported on the Any_var
type.
To allow type-safe retrieval of a value from an any
, the ORB provides the following operators for each OMG IDL type T:
// C++
Boolean operator>>=(const Any&, T&);
This function signature suffices for primitive types that are usually passed by value. For values of type T that are too large to be passed by value efficiently, the ORB provides a different signature, as follows:
// C++
Boolean operator>>=(const Any&, T*&);
The first form of this function is used only for the following types:
Boolean, Char, Octet, Short, UShort, Long, ULong, Float, Double
For all other types, the second form of the function is used.
This "right-shift-assign" operator is used to extract a typed value from an any,
as follows:
// C++
Long value;
Any a;
a <<= Long(42);
if (a >>= value) {
// ... use the value ...
}
In this case, the version of operator>>=
for type Long
determines whether the Any truly does contain a value of type Long
and, if so, copies its value into the reference variable provided by the caller and returns TRUE
. If the Any does not contain a value of type Long
, the value of the caller's reference variable is not changed, and operator>>=
returns FALSE
.
For nonprimitive types, extraction is done by pointer. For example, consider the following OMG IDL struct:
// IDL
struct MyStruct {
long lmem;
short smem;
};
Such a struct could be extracted from an Any as follows:
// C++
Any a;
// ... a is somehow given a value of type MyStruct ...
MyStruct *struct_ptr;
if (a >>= struct_ptr) {
// ... use the value ...
}
If the extraction is successful, the caller's pointer points to storage managed by the Any, and operator>>=
returns TRUE
. The caller must not try to delete
or otherwise release this storage. The caller also should not use the storage after the contents of the Any variable are replaced via assignment, insertion, or the replace
function, or after the Any variable is destroyed. Care must be taken to avoid using T_var
types with these extraction operators, since they will try to assume responsibility for deleting the storage owned by the Any.
If the extraction is not successful, the value of the caller's pointer is set equal to the null pointer, and operator>>=
returns FALSE
.
Correct extraction of array types relies on the Array_forany
types described in "Arrays" on page 11-18.
An example of the OMG IDL is as follows:
// 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
The Array_forany
types are always passed to operator>>=
by reference.
For strings and arrays, applications are responsible for checking the TypeCode of the Any to be sure that they do not overstep the bounds of the array or string object when using the extracted value.
The operator>>=
is also supported on the Any_var
type.
Since the boolean, octet, and char OMG IDL types are not required to map to distinct C++ types, another means of distinguishing them from each other is necessary so that they can be used with the type-safe Any interface. Similarly, since both bounded and unbounded strings map to char*
, another means of distinguishing them must be provided. This is done by introducing several new helper types nested in the Any class interface. For example, this is accomplished as shown below:
// 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;
};
The ORB provides the overloaded operator<<=
and operator>>=
functions for these special helper types. These helper types are used as shown here:
// 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>...
}
A bound value of 0 (zero) indicates an unbounded string.
For noncopying insertion of a bounded or unbounded string into an Any, the nocopy
flag on the from_string
constructor should be set to TRUE
:
// C++
char* p = string_alloc(8);
// ...initialize string p...
any <<= Any::from_string(p, 8, 1); // any consumes p
Assuming that boolean, char, and octet all map the C++ type unsigned
char
, the private and unimplemented operator<<=
and operator>>=
functions for unsigned
char
cause a compile-time error if straight insertion or extraction of any of the Boolean, Char, or Octet types is attempted:
// C++
Octet oct = 040;
Any any;
any <<= oct; // this line will not compile
any <<= Any::from_octet(oct); // but this one will
Sometimes it is desirable to extract an object reference from an Any as the base Object type. This can be accomplished using a helper type similar to those required for extracting Boolean, Char, and Octet:
// C++
class Any
{
public:
...
struct to_object {
to_object(Object_ptr &obj) : ref(obj) {}
Object_ptr &ref;
};
Boolean operator>>=(to_object) const;
...
};
The to_object
helper type is used to extract an object reference from an Any as the base Object type. If the Any contains a value of an object reference type as indicated by its TypeCode, the extraction function operator>>=(to_object)
explicitly widens its contained object reference to Object and returns true; otherwise, it returns false. This is the only object reference extraction function that performs widening on the extracted object reference. As with regular object reference extraction, no duplication of the object reference is performed by the to_object
extraction operator.
Under some circumstances the type-safe interface to Any is not sufficient. An example is a situation in which data types are read from a file in binary form and are used to create values of type Any. For these cases, the Any class provides a constructor with an explicit TypeCode and generic pointer:
// C++
Any(TypeCode_ptr tc, void *value, Boolean release = FALSE);
The constructor duplicates the given TypeCode pseudo-object reference. If the release
parameter is TRUE
, the Any object assumes ownership of the storage pointed to by the value
parameter. A caller should make no assumptions about the continued lifetime of the value
parameter once it has been handed to an Any with release=TRUE
, since the Any may copy the value
parameter and immediately free the original pointer. If the release
parameter is FALSE
(the default case), the Any object assumes that the caller manages the memory pointed to by value
. The value
parameter can be a null pointer.
The Any class also defines three unsafe operations:
// C++
void replace(
TypeCode_ptr,
void *value,
Boolean release = FALSE
);
TypeCode_ptr type() const;
const void *value() const;
The replace
function is intended to be used with types that cannot be used with the type-safe insertion interface, and so is similar to the constructor described above. The existing TypeCode is released and value storage is deallocated, if necessary. The TypeCode function parameter is duplicated. If the release
parameter is TRUE
, the Any object assumes ownership for the storage pointed to by the value
parameter. The Any should make no assumptions about the continued lifetime of the value
parameter once it has been handed to the Any::replace
function with release=TRUE
, since the Any may copy the value
parameter and immediately free the original pointer. If the release
parameter is FALSE
(the default case), the Any object assumes that the caller manages the memory occupied by the value. The value
parameter of the replace
function can be a null pointer.
Note that neither the constructor shown above nor the replace
function is type-safe. In particular, no guarantees are made by the compiler at run time as to the consistency between the TypeCode and the actual type of the void*
argument. The behavior of an ORB implementation when presented with an Any
that is constructed with a mismatched TypeCode and value is not defined.
The type
function returns a TypeCode_ptr
pseudo-object reference to the TypeCode associated with the Any. Like all object reference return values, the caller must release the reference when it is no longer needed, or assign it to a TypeCode_var
variable for automatic management.
The value
function returns a pointer to the data stored in the Any. If the Any has no associated value, the value
function returns a null pointer.
The default constructor creates an Any with a TypeCode of type tk_null
, and no value. The copy constructor calls _duplicate
on the TypeCode_ptr
of its Any parameter and deep-copies the parameter's value. The assignment operator releases its own TypeCode_ptr
and deallocates storage for the current value if necessary, then duplicates the TypeCode_ptr
of its Any parameter and deep-copies the parameter's value. The destructor calls release
on the TypeCode_ptr
and deallocates storage for the value, if necessary.
Other constructors are described in the section "Handling Untyped Values" on page 11-47.
The full definition of the Any class can be found in the section "Any Class Member Functions" on page 1-8
.The memory management rules and member function signatures for a user-defined type depend upon whether the type is fixed-length or variable-length. A user-defined type is variable-length if it is one of the following:
If a type is not on this list, the type is fixed-length.
Automatic variables (vars) are provided to simplify memory management. Vars are provided through a var class that assumes ownership for the memory required for the type and frees the memory when the instance of the var object is destroyed or when a new value is assigned to the var object.
The WLE provides var classes for the following types:
Using var Classes
struct, union, sequence, array, and interface
)
The var classes have common member functions, but may support additional operators depending upon the OMG IDL type. For an OMG IDL type TYPE, the TYPE_var class contains constructors, destructors, assignment operators, and operators to access the underlying TYPE type. An example var class is as follows:
The details of the member functions are as follows:
class TYPE_var
operator TYPE_ptr;
{
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&();
};
TYPE_var()
TYPE_var
class. The constructor initializes to 0 (zero) the TYPE *
owned by the var class. You may not invoke the operator-> on a TYPE_var
class unless a valid TYPE *
has been assigned to it.
TYPE_var(TYPE * Value);
Value
argument is a pointer to the TYPE to be owned by this var class. This pointer must not be 0 (zero).
TYPE_var(const TYPE_var & From);
From
parameter. When the TYPE_var is destroyed, the copy of the TYPE is released or deleted. The From
parameter specifies the var class that points to the TYPE to be copied.
~TYPE_var();
CORBA::string_free
routine. For object references, this is the CORBA::release
routine. For other types, this may be delete
or a generated static routine used to free allocated memory.
TYPE_var &operator=(TYPE * NewValue);
NewValue
parameter. If the TYPE_var currently owns a TYPE, it is released before assuming ownership of the NewValue
parameter. The NewValue
argument is a pointer to the TYPE to be owned by this var class. This pointer must not be 0 (zero).
TYPE_var &operator=(const TYPE_var &From);
From
TYPE_var parameter. If TYPE_var currently owns a TYPE, it is released. When the TYPE_var is destroyed, the copy of the TYPE is released. The From
parameter specifies the var class that points to the data to be copied.
TYPE *operator->();
TYPE *operator->() const;
operator->
until the var owns a valid TYPE. Do not try to release this return value or access this return value after the TYPE_var has been destroyed.
TYPE_var_ptr in() const;
TYPE_var_ptr& inout();
TYPE_var_ptr& out();
TYPE_var_ptr _retn();
in
parameter, call the in()
member function; for inout
parameters, the inout()
member function; for out
parameters, the out()
member function. To obtain a return value from the TYPE_var, call the _return()
function. For each TYPE
_var type, the return types of each of these functions will match the type shown in Table 11-7, "Basic Argument and Result Passing," on page 11-65 for the in
, inout
, out
, and return modes for the underlying type TYPE, respectively.
Some differences occur in the operators supported for the user-defined data types. Table 11-3 describes the various operators supported by each OMG IDL data type, in the generated C++ code. Because the assignment operators are supported for all of the data types described in Table 11-3, they are not included in the comparison.
OMG IDL Data Type | operator -> | operator[ ] |
---|---|---|
|
Yes |
No |
|
Yes |
No |
|
Yes |
Yes, non-const only |
|
No |
Yes |
The signatures are as shown in Table 11-4.
Sequence vars support the following additional operator[] member function:
TYPE &operator[](CORBA::ULong Index);
operator[]
of sequence owned by the var class. The operator[]
returns a reference to the appropriate element of the sequence at the specified index. The Index
argument specifies the index of the element to return. This index cannot be greater than the current sequence length.
Array vars do not support operator->, but do support the following additional operator[] member functions to access the array elements:
TYPE_slice& operator[](CORBA::ULong Index);
const TYPE_slice & operator[](CORBA::ULong Index) const;
Index
argument specifies the index of the slice to return. This index cannot be greater than the array dimension.
The String vars in the member functions described in this section and in the section "Sequence vars" on page 11-53 have a TYPE of char *
. String vars support additional member functions, as follows:
String_var(char * str)
String_var
from a string. The str
argument specifies the string that will be assumed. The user must not use the str
pointer to access data.
String_var(const char * str)
String_var(const String_var & var)
String_var
from a const
string. The str
argument specifies the const string that will be copied. The var
argument specifies a reference to the string to be copied.
String_var & operator=(char * str)
CORBA::string_free
, and then assumes ownership of the input string. The str
argument specifies the string whose ownership will be assumed by this String_var
object.
String_var & operator=(const char * str)
String_var & operator=(const String_var & var)
CORBA::string_free
, and then copies the input string. The Data
argument specifies the string whose ownership will be assumed by this String_var
object.
char operator[] (Ulong Index)
char operator[] (Ulong Index) const
Index
argument specifies the index of the array to use in accessing a particular character within the array. Zero-based indexing is used. The returned value of the Char operator[] (Ulong Index)
function can be used as an lvalue. The returned value of the Char operator[] (Ulong Index) const
function cannot be used as an lvalue.
Structured types (struct, union, sequence), arrays, and interfaces have a corresponding generated _out class. The out class is provided for simplifying the memory management of pointers to variable-length and fixed-length types. For more information about out
classes and the common member functions, see the section "Using out Classes" on page 11-56.
Some differences occur in the operators supported for the user-defined data types. Table 11-5 describes the various operators supported by each OMG IDL data type, in the generated C++ code. Because the assignment operators are supported for all of the data types described in Table 11-3, they are not included in the comparison.
OMG IDL Data Type | operator -> | operator[ ] |
---|---|---|
|
Yes |
No |
|
Yes |
No |
|
Yes |
Yes, non-const only |
|
No |
Yes |
The signatures are as shown in Table 11-6.
When a TYPE
_var
is passed as an out
parameter, any previous value it referred to must be implicitly deleted. To give the ORB enough hooks to meet this requirement, each T_var
type has a corresponding TYPE
_out
type that is used solely as the out
parameter type.
Note: The _out classes are not intended to be instantiated directly by the programmer. Specify an _out class only in function signatures.
The general form for TYPE
_out
types for variable-length types is as follows:
// 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&):
};
The first constructor binds the reference data member with the T*&
argument and sets the pointer to the zero (0) pointer value. The second constructor binds the reference data member with the pointer held by the
TYPE
_var
argument, and then calls delete
on the pointer (or string_free()
in the case of the String_out
type or TYPE
_free()
in the case of a TYPE
_var
for an array type TYPE
). The third constructor, the copy constructor, binds the reference data member to the same pointer referenced by the data member of the constructor argument.
Assignment from another
TYPE
_out
copies the TYPE
*
referenced by the TYPE
_out
argument to the data member. The overloaded assignment operator for TYPE
*
simply assigns the pointer argument to the data member. Note that assignment does not cause any previously held pointer to be deleted; in this regard, the TYPE
_out
type behaves exactly as a TYPE
*
. The TYPE
*&
conversion operator returns the data member. The ptr()
member function, which can be used to avoid having to rely on implicit conversion, also returns the data member. The overloaded arrow operator (operator->()
) allows access to members of the data structure pointed to by the TYPE
*
data member. Compliant applications may not call the overloaded operator->()
unless the TYPE
_out
has been initialized with a valid non-null
TYPE
*
.
Assignment to a TYPE
_out
from instances of the corresponding TYPE
_var
type is disallowed because there is no way to determine whether the application developer wants a copy to be performed, or whether the TYPE
_var
should yield ownership of its managed pointer so it can be assigned to the TYPE
_out
. To perform a copy of a TYPE
_var
to a TYPE
_out
, the application should use new
, as follows:
// C++
TYPE
_var t = ...;
my_out = new TYPE
(t.in()); // heap-allocate a copy
The in()
function called on t
typically returns a const
TYPE
&
, suitable for invoking the copy constructor of the newly allocated T
instance.
Alternatively, to make the TYPE
_var
yield ownership of its managed pointer so it can be returned in a T_out
parameter, the application should use the TYPE
_var::_retn()
function, as follows:
// C++
TYPE
_var t = ...;
my_out = t._retn(); // t yields ownership, no copy
Note that the TYPE
_out
types are not intended to serve as general-purpose data types to be created and destroyed by applications; they are used only as types within operation signatures to allow necessary memory management side-effects to occur properly.
When a _var
is passed as an out
parameter, any previous value it refers to must be implicitly released. To give C++ mapping implementations enough hooks to meet this requirement, each object reference type results in the generation of an _out
type that is used solely as the out
parameter type. For example, interface TYPE
results in the object reference type TYPE
_ptr
, the helper type TYPE
_var
, and the out
parameter type TYPE
_out
. The general form for object reference _out
types is as follows:
// 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_;
};
Sequence outs support the following additional operator[]
member function:
TYPE &operator[](CORBA::ULong Index);
operator[]
of the sequence owned by the out class. The operator[]
returns a reference to the appropriate element of the sequence at the specified index. The Index
argument specifies the index of the element to return. This index cannot be greater than the current sequence length.
Array outs do not support operator->
, but do support the following additional operator[]
member functions to access the array elements:
TYPE_slice& operator[](CORBA::ULong Index);
const TYPE_slice & operator[](CORBA::ULong Index) const;
Index
argument specifies the index of the slice to return. This index cannot be greater than the array dimension.
When a String_var
is passed as an out
parameter, any previous value it refers to must be implicitly freed. To give C++ mapping implementations enough hooks to meet this requirement, the string type also results in the generation of a String_out
type in the CORBA namespace that is used solely as the string out
parameter type. The general form for the String_out
type is as follows:
// 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&);
};
The first constructor binds the reference data member with the char*&
argument. The second constructor binds the reference data member with the char*
held by the String_var
argument, and then calls string_free()
on the string. The third constructor, the copy constructor, binds the reference data member to the same char*
bound to the data member of its argument.
Assignment from another String_out
copies the char*
referenced by the argument String_out
to the char*
referenced by the data member. The overloaded assignment operator for char*
simply assigns the char*
argument to the data member. The overloaded assignment operator for const
char*
duplicates the argument and assigns the result to the data member. Note that the assignment does not cause any previously held string to be freed; in this regard, the String_out
type behaves exactly as a char*
. The char*&
conversion operator returns the data member. The ptr()
member function, which can be used to avoid having to rely on implicit conversion, also returns the data member.
Assignment from String_var
to a String_out
is disallowed because of the memory management ambiguities involved. Specifically, it is not possible to determine whether the string owned by the String_var
should be taken over by the String_out
without copying, or if it should be copied. Disallowing assignment from String_var
forces the application developer to make the choice explicitly, as follows:
// 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
}
On the line marked with the comment "1," the caller is explicitly copying the string held by the String_var
and assigning the result to the out
argument. Alternatively, the caller could use the technique shown on the line marked with the comment "2" to force the String_var
to give up its ownership of the string it holds so that it may be returned in the out
argument without incurring memory management errors.
The mapping of parameter passing modes attempts to balance the need for both efficiency and simplicity. For primitive types, enumerations, and object references,
the modes are straightforward, passing the type P
for primitives and enumerations and the type A_ptr
for an interface type A.
Aggregate types are complicated by the question of when and how parameter memory is allocated and deallocated. Mapping in
parameters is straightforward because the parameter storage is caller-allocated and read-only. The mapping for out
and inout
parameters is more problematic. For variable-length types, the callee must allocate some if not all of the storage. For fixed-length types, such as a Point type
represented as a struct containing three floating point members, caller allocation is preferable (to allow stack allocation).
To accommodate both kinds of allocation, avoid the potential confusion of split allocation, and eliminate confusion with respect to when copying occurs, the mapping is T&
for a fixed-length aggregate T
and T*&
for a variable-length T
. This approach has the unfortunate consequence that usage for structs depends on whether the struct is fixed- or variable-length; however, the mapping is consistently T_var&
if the caller uses the managed type T_var
.
The mapping for out
and inout
parameters additionally requires support for deallocating any previous variable-length data in the parameter when a T_var
is passed. Even though their initial values are not sent to the operation, the WLE includes out
parameters because the parameter could contain the result from a previous call. The provision of the T_out
types is intended to give implementations the hooks necessary to free the inaccessible storage while converting from the T_var
types. The following examples demonstrate the compliant behavior:
// 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);
Note that implicit deallocation of previous values for out
and inout
parameters works only with T_var
types, not with other types:
// IDL
void q(out string s);
// C++
char *s;
for (int i = 0; i < 10; i++)
q(s); // memory leak!
Each call to the q
function in the loop results in a memory leak because the caller is not invoking string_free
on the out
result. There are two ways to fix this, as shown below:
// 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
}
Using a plain char*
for the out
parameter means that the caller must explicitly deallocate its memory before each reuse of the variable as an out
parameter, while using a String_var
means that any deallocation is performed implicitly upon each use of the variable as an out
parameter.
Variable-length data must be explicitly released before being overwritten. For example, before assigning to an inout
string parameter, the implementor of an operation may first delete the old character data. Similarly, an inout
interface parameter should be released before being reassigned. One way to ensure that the parameter storage is released is to assign it to a local T_var
variable with an automatic release, as in the following example:
// 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 */
}
For parameters that are passed or returned as a pointer (T*
) or as a reference to a pointer (T*&
), an application is not allowed to pass or return a null pointer; the result of doing so is undefined. In particular, a caller may not pass a null pointer under any of the following circumstances:
in
and inout
string
However, a caller may pass a reference to a pointer with a null value for out
parameters, because the callee does not examine the value, but overwrites it. A callee may not return a null pointer under any of the following circumstances:
out
and return variable-length struct
out
and return variable-length union
out
and return variable-length array, return fixed-length array
Table 11-7, "Basic Argument and Result Passing," on page 11-65 displays the mapping for the basic OMG IDL parameter passing modes and return type
according to the type being passed or returned. Table 11-8, "T_var Argument and Result Passing," on page 11-66 displays the same information for T_var
types. Table 11-8 is merely for informational purposes; it is expected that operation signatures for both clients and servers will be written in terms of the parameter-passing modes shown in Table 11-7, with the exception that the T_out
types will be used as the actual parameter types for all out
parameters.
It is also expected that T_var
types will support the necessary conversion operators to allow them to be passed directly. Callers should always pass instances of either T_var
types or the base types shown in Table 11-7, and callees should treat their T_out
parameters as if they were actually the corresponding underlying types shown in Table 11-7.
In Table 11-7, fixed-length arrays are the only case where the type of an out
parameter differs from a return value, which is necessary because C++ does not allow a function to return an array. The mapping returns a pointer to a slice of the
array, where a slice is an array with all the dimensions of the original array
specified except the first dimension.
Note: The Object reference ptr data type includes pseudo-object references. The array slice return is an array with all the dimensions of the original array except the first dimension.
A caller is responsible for providing storage for all arguments passed as in
arguments.
Note: The object reference var data type includes pseudo-object references
Table 11-9 and Table 11-10 describe the caller's responsibility for storage associated with inout
and out
parameters and for return results.
Type | Inout Param | Out Param | Return Result |
---|---|---|---|
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 |
octet |
1 |
1 |
1 |
enum |
1 |
1 |
1 |
object reference ptr |
2 |
2 |
2 |
struct, fixed |
1 |
1 |
1 |
struct, variable |
1 |
3 |
3 |
union, fixed |
1 |
1 |
1 |
union, variable |
1 |
3 |
3 |
string |
4 |
3 |
3 |
sequence |
5 |
3 |
3 |
array, fixed |
1 |
1 |
6 |
array, variable |
1 |
6 |
6 |
any |
5 |
3 |
3 |