Writing rwSaveGuts and rwRestoreGuts Functions

The next two sections discuss guidelines for writing rwSaveGuts() and rwRestoreGuts() global functions. To illustrate these guidelines, the following class will be used:

 

class Gut {

public:

int fundamentalType_;

size_t aSizeTValue_;

RWCString aRogueWaveObject_;

RWTValDlist anotherRogueWaveObject_;

RWCollectableString anRWCollectable_

RWCollectableString* pointerToAnRWCollectable_;

Gut* pointerToAnObject_;

};

The discussion in the next two sections describes how to write rwSaveGuts() and rwRestoreGuts() functions for non-templatized classes. However, the descriptions also apply to the templatized rwSaveGuts() and rwRestoreGuts() that are written for templatized classes.

Guidelines for Writing rwSaveGuts

The global overloaded functions:

 

rwSaveGuts(RWFile& f, const YourClass& t)

rwSaveGuts(RWvostream& s, const YourClass& t)

are responsible for saving the internal state of a YourClass object to either a binary file (using class RWFile) or to a virtual output stream (an RWvostream). This allows the object to be restored at some later time.

The rwSaveGuts() functions that you write must save the state of each member in YourClass, including the members of the class from which you inherited.

How you write the functions depends upon the type of the member data:

To save member data that are either C++ fundamental types (int, char, float, ...), or most Rogue Wave classes, including RWCollectable, use the overloaded insertion operator operator<<.

Since size_t is normally a typedef for one of the basic types, it cannot be handled by operator<< (it would cause an ambiguity error), so you will need to save it specifically by calling putSizeT(aSizeTValue);.

Saving members that are pointers to non RWCollectable objects can be a bit tricky. This is because it is possible that a pointer does not point to any object at all. One way of dealing with the possibility of nil pointers is to check whether a pointer points to a valid object. If the pointer is valid, save a boolean true, then save the dereferenced pointer. If the pointer is invalid, save a boolean false but don't save the pointer.

When you restore the pointer, rwRestoreGuts() first restores the boolean. If the boolean is true, then rwRestoreGuts() restores the valid pointer. If the boolean is false, then rwRestoreGuts() sets the pointer to nil.

Saving pointers to objects derived from RWCollectable is easier. It is still possible that a pointer is nil. But if you use:

 

RWvostream& operator<<(RWvostream&, const RWCollectable*);

to save the pointer, the nil pointer will be detected automatically.

Using these guidelines, you can write rwSaveGuts() functions for the example class Gut as follows:

 

void rwSaveGuts(RWvostream& stream, const Gut& gut) {

// Use insertion operators to save fundamental objects,

// Rogue Wave objects, and pointers to

// RWCollectable-derived objects.

stream << gut.fundamentalType_

stream.putSizeT(gut.aSizeTValue_);

stream

<< gut.aRogueWaveObject_

<< gut.anotherRogueWaveObject_

<< gut.pointerToAnRWCollectable_;

// The tricky saving of a pointer

// to a non-RWCollectable object.

if (gut.pointerToAnObject_ == 0) { // Is it a nil pointer?

stream << false; // Yes, don't save.

}else {

stream << true; // No, it's valid

stream << gut.pointerToAnObject_; // so save it.

}

}

void rwSaveGuts(RWFile& stream, const Gut& gut) {

// The body of this function is identical to

// rwSaveGuts(RWvostream& stream, const Gut& gut).

}

Guidelines for Writing rwRestoreGuts

The global overloaded functions:

 

rwRestoreGuts(RWFile& f, YourClass& t)

rwRestoreGuts(RWvistream& s, YourClass& t)

are responsible for restoring the internal state of a YourClass object from either a binary file (using class RWFile) or from a virtual input stream (an RWvistream).

The rwRestoreGuts() functions that you write must restore the state of each member in YourClass, including the members of the class that you inherited from. The functions must restore member data in the order that it was saved.

How you write the functions depends upon the type of the member data:

To restore member data that are either C++ fundamental types (int, char, float, ...) or most Rogue Wave classes, including RWCollectable, use the overloaded extraction operators (operator>>).

Since size_t is normally a typedef for one of the basic types, it cannot be handled by operator<< (it would cause an ambiguity error), so you will need to save it specifically by calling getSizeT(aSizeTValue);.

Restoring members that are pointers to non RWCollectable objects can be a bit tricky. This is because it is possible that a saved pointer did not point to any object at all. But if rwSaveGuts() saved a boolean flag before saving the pointer, as we described in the previous section, then it is a relatively simple matter for the rwRestoreGuts() to restore valid and nil pointers.

Assuming that the members were saved with a compatible rwSaveGuts(), when you restore the pointer, rwRestoreGuts() first restores the boolean. If the boolean is true, then rwRestoreGuts() restores the valid pointer. If the boolean is false, then rwRestoreGuts() sets the pointer to nil.

Restoring pointers to objects derived from RWCollectable is easier. It is still possible that the pointer is nil. But if you use:

 

RWvistream& operator>>(RWvistream&, const RWCollectable*&);

to restore the pointer, the nil pointer will be detected automatically.

Using these guidelines, you can write the rwRestoreGuts() functions for the example class Gut as follows:

 

void rwRestoreGuts(RWvistream& stream, const Gut& gut) {

// Use extraction operators to restore fundamental objects,

// Rogue Wave objects, and pointers to

// RWCollectable-derived objects.

stream >> gut.fundamentalType_

stream.getSizeT(gut.aSizetValue_);

stream

>> gut.aRogueWaveObject_

>> gut.anotherRogueWaveObject_

>> gut.pointerToAnRWCollectable_;

// The tricky restoring of a pointer

// to a non-RWCollectable object.

bool isValid;

stream >> isValid; // Is it a nil pointer?

if (isValid) // No,

stream >> gut.pointerToAnObject_; // restore the pointer.

else // Yes,

gut.pointerToAnObject_ = rwnil; // set pointer to nil.

}

void rwRestoreGuts(RWFile& stream, Gut& gut) {

// The body of this function is identical to

// rwRestoreGuts(RWvostream& stream, Gut& gut).

}

The order of the data is not important as long as the rwSaveGuts and rwRestoreGuts are isomorphic (See A Few Friendly Warnings for guidelines).