An IDL sequence type gets mapped to a C++ class that behaves similarly to an array type, but with a current length and a maximum length. The maximum length is fixed for a bounded sequence, and changeable in the case of an unbounded sequence, the maximum is simply an initial value set in an unbounded sequence's constructor. The details of the generated C++ class differ slightly for bounded and unbounded sequences, and this is discussed in the following sections.
A _var
type is also produced for each IDL sequence type; this can optionally be used to manage the storage of dynamically allocated sequences.
Given the following IDL typedef
typedef sequence<1ong,10> seq10;
an instance of this type can be defined as follows in C++:
seq10 x1;
Elements can be added using operator[ ]
, for example:
CORBA::ULong i; x1.length(5); for (i=O; i < 5; i++){ // Enter five elements. X1[i] = i; }
Note that the length must be set explicitly using the length( )
member function, operator [ ]
does not change the length. Note that operator [ ]
should not be used to access or change an element outside of the current length. The maximum number of elements in this sequence is fixed at 10, the bound of the sequence type. Setting the length to a value larger than the sequence's bound produces undefined behavior.
A sequence can be dynamically allocated using either of the following two statements:
seq10 pi = new seq10; seq10_var p2 = new seq10;
The difference is that the sequence pointed to by pi
must be deallocated explicitly with delete p1
, whereas the sequence pointed to by p2
is deallocated automatically when p2
goes out of scope.
The generated C++ class seq10 is declared as follows:
public:class seq10; { seq10; // Allocates space for 10 elements // and sets length to 0. seq10(const seq10&); // Deep copy. seq10(CORBA::ULong initial_length, CORBA::Long *data-buffer, CORBA::Boolean release = 0); ~seq10; seq10; operator=(const seq10&); // Deep copy. static CORBA::Long* allocbuf(CORBA::ULong number_elements); static void freebuf(CORBA::Long* data); CORBA::ULong maximum( ) const; // get the max size CORBA::ULong length( ) const; // get current length void length(CORBA::ULong new_length); CORBA::Long& operator[ ] (CORBA::ULong index); const CORBA::Long& operator[ ] (CORBA::Ulong index) const; }
The difference between a bounded and an unbounded sequence is that bounded has a fixed maximum length while unbounded has no theoretical maximum. A sequence of any length can be passed where an unbounded sequence is expected. Therefore, unbounded sequences are normally used in preference to bounded ones, unless the maximum length can be determined confidently.
In the C++ class that represents an unbounded sequence, there is a maximum( )
function that returns the sequence's current maximum. This is only an indication of the amount of space that is currently allocated to the sequence and it is normally not very important. The maximum is automatically increased if the length is increased to require more space than is currently allocated.
Given the following typedef
typedef sequence<float> seq;
an instance of this type can be defined as follows:
seq x2(50); // Initial maximum of 50.
A sequence can be dynamically allocated by either of the following two statements:
seq p1, = new seq(50); seq_var p1 = new seq(50);
The length must be set using length( )
as before, otherwise the length is zero. Elements can then be added using operator [ ]
. operator [ ]
should not be used to access or change an element outside of the current length.
An unbounded sequence defined using the following default constructor,
seq x3;
allocates some implementation-dependent amount of initial space for the sequence.
// Create the data buffer: CORBA::Long *buf = seq::allocbuf(50); // Initialize that buffer: CORBA::ULong i; for (i=O; i<27; i++) buf[i] = i; // Normal operator[]
Now create the sequence:
seq10 x2(50, 27, buf, 1); // Length is 27
The initial maximum has been set here to 50 (when the buffer is allocated and in the first parameter to the sequence's constructor). The length is 27 after this code sequence.
Continuing the example from the previous section, the generated C++ class seq
is declared as follows:
class seq { seq( ); // sets the length to zero. seq(const seq&); // Deep copy. seq(CORBA::ULong maximum); seq(CORBA::ULong maximum, CORBA::ULong initial_length, CORBA::Long *data, CORBA::Boolean release = 0); ~seq( ); seq& operator=(const seq&); // Deep copy. static CORBA::Long* allocbuf(CORBA::ULong number-elements); static void freebuf(CORBA::Long* data); CORBA::ULong maximum( ) const; // Get and set length: CORBA::ULong length( ) const; void length(CORBA::ULength new_length); CORBA::Long& operator[ ] (CORBA::ULong index); const CORBA::Long& operator[ ] (CORBA::Ulong index) const; };
When a sequence is passed as a parameter to an operation or appears as the return type, the corresponding C++ formal parameter types are used.
IDL type | in | out | inout | return |
---|---|---|---|---|
sequence s |
const S& |
S*& |
S& |
S* |
Remember that pointers are not valid IDL types, so you should not pass or return a zero pointer. It is of course valid to return (or pass as an out
parameter) a pointer to an empty sequence.
The memory management rules for sequences can be summarized as follows. For an in
parameter, the client is responsible for memory management. For an out
parameter or return value, the target object must allocate the sequence, and return a pointer to this to the client. The client must deallocate the returned sequence when it no longer needs it. For an inout
sequence, the client must allocate an initial sequence, which is passed by reference to the target object, and can be changed by it. The client remains responsible for deallocating the memory.
If the client and target object are in different address spaces, the receiver's copy of the sequence will have a release flag of 1 (so deallocating the sequence releases the buffer space). If the client and server are in the same address space, the creator of the sequence will have determined whether or not the buffer space needs to be released. If the release flag is 0, the creator must have arranged for another part of the code to release the space.