Advanced Tools Module User’s Guide : PART II Advanced Tools Module Packages : Chapter 6 Using Object Serialization : Basic Examples : Saving and Restoring an Object by Pointer
Saving and Restoring an Object by Pointer
The previous example supports only streaming objects as values. To support streaming objects as pointers requires additional changes.
First Change
Include the macros: RW_DECLARE_STREAMABLE_AS_SELF(), RW_DECLARE_STREMABALE_AS_BASE() (if your class needs to be streamed through pointers to base classes) and RW_DECLARE_STREAMABLE_POINTER() in this order in the header file for each class that is to be streamed as a pointer type. You will also have to include the RW_DECLARE_VIRTUAL_STREAM_FNS() macro described above inside the declaration of your class.
NOTE >> The call can go in any header file, as long as it’s included before code that streams this class. Putting it in the header with the class declaration is the easiest way.
The following code shows real_property with this macro added.
 
// examples\serial\simple\real_property.h
 
class real_property
{
RW_DECLARE_VIRTUAL_STREAM_FNS(real_property)
 
public:
real_property () { }
 
real_property (const RWCString& address,
const RWCString& size)
:address_(address), size_(size) {
}
 
virtual ~real_property() { }
 
bool
operator== (const real_property&prop) const {
return address_ == prop.address_;
}
 
private:
RWCString address_;
RWCString size_;
};
 
RW_DECLARE_STREAMABLE_AS_SELF(real_property)
RW_DECLARE_STREAMABLE_POINTER(real_property) // 1
//1 Place these macros after the class declaration.
The first macro declares the class' factory (which allows objects to be created on the fly from the stream) when streaming objects through pointers to this class.
The second macro declares the operators operator<<(RWObjectOutputStream&, const real_property*) and operator>>(RWObjectInputStream&, real_property*&). These allow a pointer to a real_property to be written out, and a new real_property instance to be automatically created when the stream is read back in.
Second Change
Place RW_DEFINE_STREAMABLE_AS_SELF() and RW_DEFINE_STREAMABLE_POINTER() and RW_DEFINE_STREAMABLE_AS_SELF() macros in the source file which implements the rest of the class. These macros would normally go in the same source file as the streamContents() defining macros, as shown in the following code:
 
// examples\serial\simple\real_property.cpp
 
RW_BEGIN_STREAM_CONTENTS(real_property)
{
RW_STREAM_ATTR_MEMBER(address, address_)
RW_STREAM_ATTR_MEMBER(size, size_)
}
RW_END_STREAM_CONTENTS
 
RW_DEFINE_STREAMABLE_AS_SELF(real_property)
RW_DEFINE_STREAMABLE_POINTER(real_property)
Third Change
After adding these macros, use the new pointer-based operators to write a real_property pointer to an object stream, and then read it back. Note that the serialization factory has constructed a new real_property instance that is now owned by the module calling the input operator. The following is an example of writing a real_property pointer into a file and then reading it back again.
 
// examples\serial\simple\real_estate2.cpp
 
real_property real1("1980 Main St. Corvallis, Oregon","50x100");
real_property* real2 = 0;
{
ofstream fout(“real_estate2.dat”);
RWpostream postr(fout);
 
RWObjectOutputStream out = RWCompactObjectOutputStreamImp::
make(RWDataToVirtualOutputStreamImp::
make(postr)); // 1
out << &real1; // 2
}
 
ifstream fin("real_estate2.dat");
RWpistream pistr(fin); // 3
 
RWObjectInputStream in = RWCompactObjectInputStreamImp::
make(RWDataFromVirtualInputStreamImp::
make(pistr)); // 4
 
in >> real2; // 5
//1 Create a data stream using the standard file stream just opened and then create a compact object output stream from the data stream. The second parameter indicates the kind of object that will serve as the root element.
//2 Stream out the real_property object by reference.
//3 Open the file for input.
//4 Create a data stream and then create a compact object input stream from the data stream.
//5 Read the data back in to a fresh real_property object. The input stream allocates and constructs a new real_property object as part of the extraction process. Any address held by real2 prior to that operation is lost.
A Caution on Using Streaming Pointers
Take special caution when dealing with streaming pointers. The Serial package cannot determine what kind of memory a pointer points to, and cannot determine when, or if, it is safe to delete that memory. For this reason, you need to manually manage the memory associated with pointers before streaming into them.
NOTE >> The Serial package does not manage the memory associated with streaming pointers. To avoid a memory leak, you must manually manage the memory associated with pointers before and after streaming into them.
In particular, before streaming into a pointer, ensure that the pointer is not the only reference to a heap-allocated block of memory. If it is, the pointer value will be overwritten when the serialized pointer is streamed in, and the only reference to the heap memory will be lost. This will result in a memory leak as well as other potentially unexpected behavior.
After the pointer object has been streamed in, ensure that any memory allocated by the stream is deallocated appropriately. A streamed null pointer will set the pointer's value to 0 when it is streamed in.