Object I/O |
To stream objects, use operator>>
and operator<<
. By streaming objects, you can store them persistently or send them between
processes. This section explains how to use the basic features of binary object
I/O. Later sections in this chapter describe how to add binary streaming support
to your classes.
To write an object, use operator<<
. An encoded copy of the object, along with size and type information, are
written.
To read an object into an
existing destination object, use operator>>
with the destination as the argument. The destination's previous value is
replaced. If the type of the original object and the destination are not the
same, an error is generated.
In the following example, a time and a date object are written to a file using binary object I/O. When these objects are retrieved, the second read fails due to a type mismatch.
Because the Universal Streaming Service does not require modification of the class, USS extensions to classes can be maintained in separate headers and object code files. As a convention, Recursion Software <ToolKits> place USS header files in <ospace/uss>. In the following example, <ospace/uss/time.h> is included to USS-enable the classes in Time<ToolKit>. Refer to the class catalog entry for a specific Recursion Software class to determine whether it is USS-enabled and to locate the correct header file.
#include <fstream>
#include <ospace/stream.h>
#include <ospace/time.h>
#include <ospace/uss/time.h>
void
write()
{
fstream file( "objio1.bin", ios::binary | ios::out | ios::trunc );
os_bstream stream( os_adapter_for( file ) );
os_time time = os_time::now();
os_date date = os_date::today();
cout << "Write " << time << ", " << date << endl;
stream << time << date; // Write two objects in binary format.
}
void
read()
{
fstream file( "objio1.bin", ios::binary | ios::in );
os_bstream stream( os_adapter_for( file ) );
os_time time;
stream >> time; // Read an os_time into time.
cout << "Read " << time << endl;
os_time_and_date time_and_date;
// Attempt to read an os_date into an os_time_and_date.
stream >> time_and_date;
cout << "Read " << time_and_date << endl;
}
void
main()
{
os_streaming_toolkit init_streaming;
os_time_toolkit init_time;
try
{
write();
read();
}
catch( os_streaming_toolkit_error& e )
{
cout << "Caught os_streaming_toolkit_error : " << endl;
cout << '\t' << e.what() << endl;
cout << '\t' << e.description( e.code() ) << endl;
}
}
Write 15:11:37.798917, 09/23/96
Read 15:11:37.798917
Caught os_streaming_toolkit_error :
type_mismatch: Tried to read os_time_and_date but got os_date
[bstream.cpp:1295]
Attempted to read wrong type.
To read an object onto the heap,
use operator>>
with an appropriate pointer type as the argument. The C++ pointer
compatibility rules apply. An object of a particular class can be read into
the heap using a pointer to that class or any of its base classes. The pointer
is set to zero if an error, end-of-input condition, or zero pointer occurs
during the read.
#include <fstream>
#include <ospace/stream.h>
#include <ospace/time.h>
#include <ospace/uss/time.h>
void
write()
{
fstream file( "objio2.bin", ios::binary | ios::out | ios::trunc );
os_bstream stream( os_adapter_for( file ) );
os_time time = os_time::now();
os_time_and_date time_and_date = os_time_and_date::now();
cout << "Write " << time << ", " << time_and_date << endl;
stream << time << time_and_date;
}
void
read()
{
fstream file( "objio2.bin", ios::binary | ios::in );
os_bstream stream( os_adapter_for( file ) );
os_time* time;
stream >> time; // Read an os_time into the heap.
cout << "Read " << *time << endl;
delete time; // Deallocate time.
stream >> time; // ERROR, since os_time* is not an os_time_and_date*
cout << "Read " << *time << endl;
delete time;
}
void
main()
{
os_streaming_toolkit init_streaming;
os_time_toolkit init_time;
try
{
write();
read();
}
catch( os_streaming_toolkit_error& e )
{
cout << "Caught os_streaming_toolkit_error : " << endl;
cout << '\t' << e.what() << endl;
cout << `\t' << e.description( e.code() ) << endl;
}
}
Write 15:17:31.338124, 09/23/96 15:17:31.338493
Read 15:17:31.338124
Caught os_streaming_toolkit_error :
type_mismatch: Cannot cast from os_time_and_date to os_time [class.cpp:477]
Attempted to read wrong type.
Note that the os_bstream
class considers references as objects not as pointers. When reading and
writing with references, they behave as object instances not as pointers.
When writing an object via a pointer, the pointed-to object is written along with size and type information, or a special indicator is written if the pointer is zero.
If an object is written via a
pointer, it can only be read into another pointer on the heap using operator>>
. If you write an object using a pointer and do not
read it into a pointer, a runtime error occurs.
The following example
illustrates how to write a zero pointer and safely read it as zero. The date2
object is written using a pointer and read into an actual instance of os_date
, illustrating a type mismatch error.
#include <fstream>
#include <ospace/stream.h>
#include <ospace/time.h>
#include <ospace/uss/time.h>
void
write()
{
fstream file( "objio3.bin", ios::binary | ios::out | ios::trunc );
os_bstream stream( os_adapter_for( file ) );
os_time time = os_time::now();
os_date* date1 = 0; // nil.
os_date* date2 = new os_date( os_date::august, 21, 1968 );
cout << "Write " << time << ", " << date1 << ", " << *date2 << endl;
stream << &time << date1 << date2; // Write objects via pointers.
delete date2;
}
void
read()
{
fstream file( "objio3.bin", ios::binary | ios::in );
os_bstream stream( os_adapter_for( file ) );
os_time* time;
stream >> time; // Read an os_time into the heap
cout << "Read " << *time << endl;
delete time; // Deallocate time.
os_date* date1;
stream >> date1; // Read nil into date1.
cout << "Read " << date1 << endl;
os_date date2;
// Read os_date into date2. ERROR, since written using a ptr.
stream >> date2;
cout << "Read " << date2 << endl;
}
void
main()
{
os_streaming_toolkit init_streaming;
os_time_toolkit init_time;
try
{
write();
read();
}
catch( os_streaming_toolkit_error& e )
{
cout << "Caught os_streaming_toolkit_error : " << endl;
cout << '\t' << e.what() << endl;
cout << '\t' << e.description( e.code() ) << endl;
}
}
Write 15:23:17.973520, 0x0, 08/21/68
Read 15:23:17.973520
Read 0x0
Caught os_streaming_toolkit_error :
type_mismatch: Tried to read os_date but got os_date* [bstream.cpp:1295]
Attempt to read wrong type.
An object may be written and read via a pointer to one of its base classes; the binary streaming system always performs the C++ regular type checking rules.
In the following hierarchy, the cat
class inherits from the pet class.

The next example writes an
instance of cat via a pointer to pet
, and then reads the instance of cat into a
pointer to pet . The full source code is listed
later in this section.
#include "cat.h"
#include <fstream>
#include <ospace/stream.h>
void
write()
{
fstream file( "objio4.out", ios::binary | ios::out | ios::trunc );
os_bstream stream( os_adapter_for( file ) );
pet* my_pet = new cat; // Create a cat on the heap.
my_pet->name_ = "Agatha";
cout << "Write ";
my_pet->print(); // Print the cat.
stream << my_pet;
delete my_pet;
}
void
read()
{
fstream file( "objio4.out", ios::binary | ios::in );
os_bstream stream( os_adapter_for( file ) );
pet* my_pet = 0;
stream >> my_pet; // Stream the pet onto the heap.
cout << "Read ";
my_pet->print(); // Print the pet.
delete my_pet;
}
void
main()
{
os_streaming_toolkit initialize;
write();
read();
}
Write short hair cat called Agatha
Read short hair cat called Agatha
When an object that contains pointers to other objects is written and restored, the object's morphology is maintained. All directly or indirectly pointed-to objects are written only once, and the object pointers are correctly restored when the object is read.
For example, consider a class
called person that contains two data members. The
first data member holds the person's name as a string, and the second data
member holds a pointer to the person's buddy, which is another person object.
If two persons are reciprocal buddies, the object graph looks like the
following.

If streaming a pointer to an object precipitated a blind writing of the object, an endless loop would occur. Each person would stream a buddy until the storage medium overflowed.
To prevent this problem, Streaming<ToolKit> records information about each object as it is written. After an object is written once, subsequent writes create a special reference to the object instead of writing the object repeatedly. Special references are detected during the reading process and are processed.
The following example illustrates
the way in which morphology is maintained. The address of each object is
printed to show that the mutual pointer relationships are correctly restored.
The full source code of person is presented later
in this chapter.
#include "person.h"
#include <fstream>
#include <ospace/stream.h>
void
write()
{
fstream file( "objio5.out", ios::binary | ios::out | ios::trunc );
os_bstream stream( os_adapter_for( file ) );
person* p1 = new person;
p1->name_ = "Graham";
person* p2 = new person;
p2->name_ = "David";
p1->buddy_ = p2; // David is Graham's buddy.
p2->buddy_ = p1; // Graham is David's buddy.
stream << p1; // Stream p1 and its associated data members.
delete p1;
delete p2;
}
void
read()
{
fstream file( "objio5.out", ios::binary | ios::in );
os_bstream stream( os_adapter_for( file ) );
person* p1;
stream >> p1; // Restore person and its associated data members.
person* p2 = p1->buddy_; // Who is p1's buddy?
cout << "p1 = " << p1->name_ << " @ " << p1 << endl;
cout << "buddy = " << p1->buddy_->name_ << " @ " << p1->buddy_;
cout << endl << endl;
cout << "p2 = " << p2->name_ << " @ " << p2 << endl;
cout << "buddy = " << p2->buddy_->name_ << " @ " << p2->buddy_;
cout << endl;
delete p1;
delete p2;
}
void
main()
{
os_streaming_toolkit initialize;
write();
read();
}
p1 = Graham @ 0x85de8
buddy = David @ 0x86e48
p2 = David @ 0x86e48
buddy = Graham @ 0x85de8
Morphology is also important if there are multiple references to the same object. One example is a collection of pointers with multiple identical pointers. Without correct morphology behavior in the stream, the read would produce a separate copy of the object for each duplicate pointer to that object, rather than correctly assigning all pointers to point to a single object.
The following rules describe the way in which Streaming<ToolKit> maintains morphology.
For example, if you have an object with a pointer stored in two vectors, and you stream out one vector and then the next vector, when you stream them in, the original object has a separate instance for each vector.
However, if you place both vectors in another class and stream it, the object is shared. Morphology is maintained for all objects streamed recursively as a result of a single user write.
person& is type compatible
with person , not person*
. Thus, a reference acts as an object for reading and writing purposes,
but does not act as an object pointer.Copyright©1994-2026 Recursion
Software LLC
All Rights Reserved - For use by licensed users only.