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 class encapsulates a void* pointer and a CORBA::TypeCode object that describes the thing being pointed to by the void*.
The Any type can be used with many of the CORBA types. It is useful when different types can be used that are unknown to the receiver of the data or also used as a common storage mechanism for passing a variety of types. The Any type can be used with many of the CORBA types. However, it has a unique method of redirection for setting and retrieving data.
The following data 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 explicitly 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 the topic 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];
A C++ class, similar to the following, is emitted for the LongArray:
typedef CORBA::Long LongArray[4][5]; typedef CORBA::Long LongArray_slice[5]; class LongArray_forany { public: LongArray_forany(); LongArray_forany(LongArray_slice*, CORBA::Boolean nocopy=0); LongArray_forany(const LongArray_forany ); ... }; void operator<<=(Any& , const LongArray_forany& ); CORBA::Boolean operator>>=(const Any& , LongArray_forany& );
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 returned when the data is extracted.
When a reference to non-primitive (constructed) data is inserted into an Any, a copy is made. In this case, the caller retains ownership of the original data. When a pointer to non-primitive (constructed) data is inserted into an Any, no copy is made. In this case, the Any takes ownership of the storage and caller is forbidden from accessing the storage. When the data is extracted from the Any, the caller is given a pointer that locates the data, but the Any owns the data. The caller should not free this data or reference it after the Any has been given a new value.
The following are examples of the emitted insertion and extraction signatures:
void operator <<=(Any&, const T*;); // insertion by pointer void operator <<=(Any&, const T&); // insertion by reference CORBA::Boolean operator>>=(const Any&, const T*&); // extraction
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 that follows is used in the succeeding example. It defines a struct and an array that is 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