Документ взят из кэша поисковой машины. Адрес оригинального документа : http://rtm-cs.sinp.msu.ru/manual/mico/doc/node58.html
Дата изменения: Mon Jun 7 21:54:59 1999
Дата индексирования: Mon Oct 1 21:22:39 2012
Кодировка:
Unions next up previous
Next: Interface inheritance Up: C++ mapping Previous: Arrays

Unions

Unions and structs in the CORBA-IDL allow the definition of constructed data types. Each of them is defined through a set of members. Is a struct used as an input parameter of an operation, all of its members will be transmitted, whereas for a union at most one of its members will actually be transmitted. The purpose of an IDL-union is similar to that of a C-union: reduction of memory usage. This is especially important in a middleware platform where less memory space for a data type also means less data to transfer over the network. One must carefully consider, when structs or unions should be used.

A special problem arises with unions when they are being used as parameters of operation invocations: how does the receiving object know which of the different members holds a valid value? In order to make a distinction for this case, the IDL-union is a combination of a C-union and a C-switch statement. Each member is clearly tagged with a value of a given discriminator type (see also mico/test/idl/21):

  // IDL
  typedef octet Bytes[64];
  struct S { long len; };
  interface A;

  union U switch (long) {
    case 1: long x;
    case 2: Bytes y;
    case 3: string z;
    case 4:
    case 5: S w;
    default: A obj;
  };

In the union U as shown above, long is the discriminator type. The values following the case label must belong to this discriminator type. All integer types and enums are valid discriminator types. Unions map to C++ classes with access functions for the union members and discriminant. The default union constructor performs no application-visible initialization of the union. It does not initialize the discriminator, nor does it initialize any union members to a state useful to an application. It is therefore an error for an application to access the union before setting it. The copy constructor and assignment operator both perform a deep-copy of their parameters, with the assignment operator releasing old storage if necessary. The destructor releases all storage owned by the union. The following example helps illustrate the mapping for union types for the union U as shown above:

  // Generated C++ code
  typedef CORBA::Octet Bytes[64];
  typedef CORBA::Octet Bytes_slice;
  template<...> Bytes_forany;
  struct S { CORBA::Long len; };
  typedef ... A_ptr;

  class U {
    public:
      //...
      void _d( CORBA::Long );
      CORBA::Long _d() const;

      void x( CORBA::Long );
      CORBA::Long x() const;

      void y( Bytes );
      Bytes_slice *y() const;

      void z( char* );             // free old storage, no copy
      void z( const char* );       // free old storage, copy
      void z( const String_var& ); // free old storage, copy
      const char *z() const;

      void w( const S & ); // deep copy
      const S &w() const;  // read-only access
      S &w();              // read-write access

      void obj( A_ptr ); // release old objref, duplicate
      A_ptr obj() const; // no duplicate
  };

The union discriminant access functions have the name _d to both be brief and avoid name conflicts with the members. The _d discriminator modifier function can only be used to set the discriminant to a value within the same union member. In addition to the _d accessors, a union with an implicit default member provides a _default() member function that sets the discriminant to a legal default value. A union has an implicit default member if it does not have a default case and not all permissible values of the union discriminant are listed.

Setting the union value through an access function automatically sets the discriminant and may release the storage associated with the previous value. Attempting to get a value through an access function that does not match the current discriminant results in undefined behavior. If an access function for a union member with multiple legal discriminant values is used to set the value of the discriminant, the union implementation will choose the value of the first case label in the union (e.g. value 4 for the member w of union U), although it could be any other value for that member as well.

The restrictions for using the _d discriminator modifier function are shown by the following examples, based on the definition of the union U shown above:

  // C++
  S s = ...;
  A_ptr a = ...;
  U u;

  u.w( s );   // member w selected, discrimintator == 4
  u._d( 4 );  // OK, member w selected
  u._d( 5 );  // OK, member w selected
  u._d( 1 );  // error, different member selected
  u.obj( a ); // member obj selected
  u._d( 7 );  // OK, member obj selected
  u._d( 1 );  // error, different member selected

As shown here, the _d modifier function cannot be used to implicitly switch between different union members. The following shows an example of how the _default() member function is used:

  // IDL
  union Z switch(boolean) {
    case TRUE: short s;
  };

  // C++
  Z z;
  z._default();  // implicit default member selected
  CORBA::Boolean disc = z._d(); // disc == FALSE
  U u;           // union U from previous example
  u._default();  // error, no _default() provided

For union Z, calling the _default() member function causes the union's value to be composed solely of the discriminator value of FALSE, since there is no explicit default member. For union U, calling _default() causes a compilation error because U has an explicitly declared default case and thus no _default() member function. A _default() member function is only generated for unions with implicit default members.

For an array union member, the accessor returns a pointer to the array slice, where the slice is an array with all dimensions of the original except the first (see section 5.3 for a discussion on array slices). The array slice return type allows for read-write access for array members via regular subscript operators. For members of an anonymous array type, supporting typedefs for the array are generated directly into the union. For example:

  // IDL
  union U switch (long) {
    case 1: long array[ 3 ][ 4 ];
  };

  // Generated C++ code
  class U {
    public:
    // ...
    typedef long _array_slice[ 4 ];
    void array( long arg[ 3 ][ 4 ] );
    _array_slice* array();
  };

The name of the supporting array slice typedef is created by prepending an underscore and appending _slice to the union member name. In the example above, the array member named _array results in an array slice typedef called _array_slice nested in the union class.


next up previous
Next: Interface inheritance Up: C++ mapping Previous: Arrays

Arno Puder
Mon Jun 7 10:53:40 PDT 1999