[Enterprise Extensions only]

C++ bindings for CORBA Any type

The purpose of the IDL "any" type is to encapsulate data of some arbitrary IDL type. The C++ bindings provide a C++ class named CORBA::Any that provides this functionality. A CORBA::Any object encapsulates a void* pointer and a CORBA::TypeCode object that describes the thing pointed to by the void*.

The Any type can be used with many of the CORBA types and is useful where different types can be used that are unknown to the receiver of the data, or as a common storage mechanism for passing a variety of types. It is used easily with many of the CORBA types but has a unique method of redirection operators for setting and retrieving data.

The following types are handled in this manner:

For example:

::CORBA::Any anything;
anything <<= (::CORBA::Long) 123456;
::CORBA::Long anythingStart  = 123456;
::CORBA::Long anythingLongResult = 0;
policyVar->anything(anything);
 
::CORBA::Any_var anythingResult_var(policyVar->anything());
::CORBA::Any anythingResult(anythingResult_var);
anythingResult >>= anythingLongResult;
if ( anythingStart != anythingLongResult)
{
   cout << "Anything not set" << endl;
      return 1;
}
else
{
   cout << "Anything set correctly..." << endl;
}

There are also specialized structures provided for the following types for conversion with Any:

The data in an Any object is initialized and accessed using insertion (<<=) and extraction (>>=) operators defined by the C++ bindings. These operators are provided (using overloading) by CORBA::Any for each primitive data type, and are provided by the generated C++ bindings for each user-defined IDL type. As a result, there is usually no need to indicate a typecode when inserting or extracting data from a CORBA::Any (although the CORBA::Any class does provide methods for manipulate the data using an explicit TypeCode).

Types that cannot be distinguished by C++ overloading are inserted into and extracted from Any's using special wrapper classes. These wrapper classes are not transparent to the application; the application must explicit create and use them when inserting or extracting ambiguous types into or from Any's. For primitive IDL types that do not map to distinct C++ types (boolean, octet, and char), the wrapper classes are defined within the CORBA::Any scope; they are called from_boolean, to_boolean, from_octet, to_octet, from_char, and to_char. For information on the scope, see IDL name scoping. Because bounded strings cannot be distinguished in C++ from unbounded strings, CORBA::Any provides the from_string and to_string wrapper classes, for inserting/extracting bounded strings. For extracting object references from Any's as the base CORBA::Object type, CORBA::Any provides a to_object wrapper class.

For application-specific arrays, the bindings provide a special forany class, for inserting or extracting the array into or from an Any. For example, here is an IDL array definition:

typedef long LongArray[4][5];

For this array definition, the emitted bindings define the following:

typedef CORBA::Long LongArray[4][5];
typedef CORBA::Long LongArray_slice[5];
typedef LongArray_slice* LongArray_slice_vPtr;
typedef const LongArray_slice* LongArray_slice_cvPtr;
class LongArray_forany 
{
   public:
   LongArray_forany();
   LongArray_forany(LongArray_slice*, CORBA::Boolean nocopy=0);
   LongArray_forany(const LongArray_forany );
   LongArray_forany   operator= (LongArray_slice*);
   LongArray_forany   operator= (const LongArray_forany  );
   ~LongArray_forany();
   const LongArray_slice  operator[] (int) const;
   const LongArray_slice  operator[] (CORBA::ULong) const;
   LongArray_slice   operator[] (int);
   LongArray_slice   operator[] (CORBA::ULong);
   operator LongArray_slice_cvPtr () const;
   operator LongArray_slice_vPtr  ();
};
void operator<<=(Any , const LongArray_forany  );
CORBA::Boolean operator>>=(Any , LongArray_forany  );
Note: The nocopy optional parameter of the _forany's second constructor indicates whether the _forany makes a copy of the input array or assumes ownership of it. (The default is for the _forany to assume ownership of the input array; that ownership will then be transferred to the Any when the _forany is inserted into the Any.)

To determine what kind of data is in Any, invoke the type method on a CORBA::Any to access a TypeCode that describes the data it holds. Alternatively, you can try to extract data of a particular type from the Any; the extraction operator returns a boolean to indicate success. If the extraction operation fails, the Any does not hold data of the type you tried to extract.

A CORBA::Any object always owns the data that its void* points to, and deletes (or releases) it when the Any is given a new value or deleted. The only question is whether this data is a copy of the data that was inserted into the Any. When primitives (including strings and enums) are inserted, a copy is made, and a copy is returned when the data is extracted.

For non-primitive (constructed) data, extraction from an Any always updates a pointer (owned by the caller) so that it points to the data owned by the Any. The caller should not, therefore, free this data or reference it after the Any has been given a new value or deleted. For constructed IDL type T, the emitted bindings define the following extraction operator:

CORBA::Boolean operator>>=(Any&, T*&);

When a reference to constructed data is inserted into an Any (when the C++ syntax looks as if you are inserting a value instead of a pointer) a copy is made. In this case, the caller retains ownership of the original data. For example, for constructed type T and interface I, the emitted bindings define the following insertion operators, which copy (or, in the case of object references, _duplicate) the inserted value):

void operator<<=(Any&, const T&);
void operator<<=(Any&, T_ptr);

When a pointer to constructed data is inserted into an Any, as when using the following insertion operators emitted for type T and interface I:

void operator<<=(Any&, T*);
void operator<<=(Any&, T_ptr*);

The Any takes ownership of the constructed type's top-level storage only; however, the Any makes no copy of the top-level storage or any embedded storage. All further use of the pointer that was inserted is forbidden; the Any now owns it and is free to delete it at any time. The next time data is inserted into the Any, or when the Any is destroyed, the Any deletes the previously-inserted pointer. However, if the constructed type consists of multiple dynamically-allocated regions of memory, only the top-level storage is deleted. (The Any deletes arrays using a single array delete; other constructed types are deleted using a single, normal delete.) Further, the top-level storage is deleted as a void*, rather than its true type, which means that the constructed type's destructor will not be run. Due to these restrictions, insertion by pointer of constructed types into an Any should be used with caution.

In summary, when extracting data from an Any, the caller does own the data for primitive types, but does not own the data for constructed types. When inserting data into an Any, the caller retains ownership of the data for primitive types, for constructed types inserted by value, and for storage embedded within constructed types inserted by pointer. The caller does not retain ownership of the top-level contiguous storage for a constructed type inserted into an Any by pointer.

The followng is an example that illustrates the previously discussed aspects of CORBA::Any usage. The IDL for this example appears immediately below. It defines a struct and an array that will be inserted into an Any.

Module M 
{
   Struct S 
   {
      string str;
      longlng;
   };
   typedef long long1[2][3];
}

A C++ program illustrating Any insertion and extraction appears below:

#include stdio.h
#include any_C.cpp
main()
{
   CORBA::Any a;  // the Any that we'll be using
   // test a long
   long l = 42;
   a <<= l;
   if (a.type()->equal(CORBA::_tc_long)) 
   {
      long v;
      a >>= v;
      printf("the any holds a long = %d\n", v);
   } 
   else
   printf("failure: long insertion\n");
   // test a string
   char *str = "abc";
   a <<= str;
   if (a.type()->equal(CORBA::_tc_string)) 
   {
      char *ch;
      a >>= ch;
      printf("the any holds the string = %s\n", ch);
      delete ch;
      a >>= ch;
      printf(" the any still holds the string = %s\n", ch);
      delete ch;
   }
   else
   printf("failure: string insertion\n");
   // test a bounded string -- note you do not use a typecode here
   char *bstr = "abcd";
   char *rstr;
   a <<= CORBA::Any::from_string(bstr, 6);
   if (a >>= CORBA::Any::to_string(rstr,6))
   printf("the any holds a bounded string<6> = %s\n", rstr);
   else
   printf("failure: bounded string insertion\n");
       
   // test a user-defined struct
   M::S *s1 = new M::S;
   char *saveforlater = CORBA::string_dup("abc");
   s1->str = saveforlater;
   s1->lng = 42;
   a <<= s1; // insertion by pointer
   if (a.type()->equal(_tc_M_S)) 
   {
      M::S *sp;
      a >>= sp;
      printf("the any holds an M::S = {%s, %d}\n", sp->str, sp->lng);
   }
   else
   printf("failure: struct insertion by pointer\n");
   M::S s2;
   s2.str = CORBA::string_dup("def");
   s2.lng = 23;
   a <<= s2; // note: this deletes *s1, but not saveforlater
   printf("saveforlater still = %s\n", saveforlater);
   CORBA::string_free(saveforlater);
   if (a.type()->equal(_tc_M_S)) 
   {
      M::S *sp;
      a >>= sp;
      printf("the any holds an M::S = {%s, %d}\n", sp->str, sp->lng);
   }
   else
   printf("failure: struct insertion by value\n");
   M::S_var s3 = new M::S;
   s3->str = CORBA::string_dup("ghi");
   s3->lng = 96;
   a <<= *s3; 
   if (a.type()->equal(_tc_M_S)) 
   {
      M::S *sp;
      a >>= sp;
      printf("the any holds an M::S = {%s, %d}\n", sp->str, sp->lng);
   }
   else
   printf("failure: struct insertion by ref to value\n");
   // test an array
   M::long1_var l1v =  M::long1_alloc();
   for (i=0;i<2;i++)
   for (j=0;j<3;j++)
   l1v[i][j] = (i+1)*(j+1);
   a <<= M::long1_forany(l1v);
   if (a.type()->equal(_tc_M_long1)) 
   {
      M::long1_forany l1s;
      a >>= l1s;
      printf("the any holds the array: ");
      for (i=0;i<2;i++)
      for (j=0;j<3;j++)
      printf("%d ",l1s[i][j]);
      printf("\n");
   }
   else printf("failure: array insertion\n");
}

Output from the above program is:

the any holds a long = 42
the any holds a string = abc
the any still holds a string = abc
the any holds a bounded string<6> = abcd
the any holds an M::S = {abc, 42}
saveforlater still = abc
the any holds an M::S = {def, 23}
the any holds an M::S = {ghi, 96}
the any holds the array: 1 2 3 2 4 6