[ Pobierz całość w formacie PDF ]non-garbage collected environment. This is an unacceptable burden and a violation of the "pay as you go" principle.
The conclusion that can be drawn from this discussion is that garbage collection cannot be optional. It is nearly
impossible to write efficient and reliable programs that work in both environments. Either automatic garbage
collection needs to be an integral part of the language, or it is totally out (as is the case in C++ at present).
Time-Critical Applications
Garbage collection cannot be optional, as you have observed. Why not make it an integral part of the language?
Real-time systems are based on deterministic time calculations. For example, a function that has to execute within a
time slot of 500 microseconds should never exceed its allotted time slice. However, the garbage collection process is
non-deterministic -- it is impossible to predict when it will be invoked, and how long it will take. Therefore,
file:///D|/Cool Stuff/old/ftp/1/1/ch14/ch14.htm (7 von 18) [12.05.2000 14:46:48]
ANSI/ISO C++ Professional Programmer's Handbook - Chapter 14 - Concluding Remarks and Future Directions
languages that offer automatic garbage collection are usually disqualified for use in time-critical applications. Note
that real-time programming is not confined to missile launching and low-level hardware manipulation; most modern
operating systems include time-critical components that control the allocation of system resources among processes
and threads. Many communication systems are also deterministic by nature. Adding an automated garbage collector
to C++ would disqualify it from being used in such application domains. Because a toggled garbage collector is also
impractical, C++, by design, is not a garbage collected language at present. Notwithstanding the difficulties involved
in garbage collection, there are some serious discussions of adding garbage collection to C++. It is too early to
determine if and when this will happen.
Object Persistence
Persistent objects can be stored in nonvolatile storage and used later in other runs of the same program or in other
programs. Storing the contents of an object in persistent storage is called serialization. The process of reconstituting
a serialized object from a persistent repository is called deserialization, or reconstitution. Other object-oriented
languages support object persistence directly by means of a library or built-in keywords and operators. C++ does not
support object persistence directly. Designing an efficient, general purpose, platform-independent model of object
persistence is quite a challenge. This section exemplifies handmade solutions that make up for the lack of language
support for persistence. The difficulties and complications that are associated with a handmade object persistence
model demonstrate the importance of language support.
Serialization and Deserialization of Concrete Objects
Consider the following class:
class Date
{
private:
int day;
int month;
int year;
//constructor and destructor
public:
Date(); //current date
~Date();
//...
};
Storing a Date object is a rather straightforward operation: Every data member is written to a persistent stream
(usually this is a local disk file, but it can also be a file on a remote computer). The data members can be read from
the stream at a later stage. For that purpose, two additional member functions are required, one for storing the object
and the other for reading the stored object:
#include
using namespace std;
class Date
{
//...
virtual ofstream& Write(ofstream& archive);
virtual ifstream& Read(ifstream& archive);
};
ofstream& Date::Write(ofstream& archive)
file:///D|/Cool Stuff/old/ftp/1/1/ch14/ch14.htm (8 von 18) [12.05.2000 14:46:48]
ANSI/ISO C++ Professional Programmer's Handbook - Chapter 14 - Concluding Remarks and Future Directions
{
archive.write( reinterpret_cast (&day), sizeof(day));
archive.write( reinterpret_cast (&month), sizeof(month));
archive.write( reinterpret_cast (&month), sizeof(year));
return archive;
}
ifstream& Date::Read(ifstream& archive)
{
archive.read( reinterpret_cast (&day), sizeof(day));
archive.read( reinterpret_cast (&month), sizeof(month));
archive.read( reinterpret_cast (&month), sizeof(year));
return archive;
}
In addition to the member functions Read() and Write(), it is necessary to define a reconstituting constructor,
which reads a serialized object from a stream:
Date::Date(ifstream& archive) //reconstituting constructor
{
Read(arcive);
}
Class Hierarchies
For concrete classes such as Date, whose members are fundamental types, making up for the lack of standardized
persistence facilities is rather straightforward. The serialization and deserialization operations merely store and read
data members, respectively. Note that the class's member functions are not serialized. This is not a major issue of
concern because the serialized object should be a close approximation of the binary representation of the object in
memory.
Handling derived classes and classes that contain member objects is more complicated: The member functions
Read() and Write() need to be redefined in every class in the hierarchy. Likewise, a reconstituting constructor
is required for every class, as in the following example:
class DateTime: public Date
{
private:
int secs;
int minutes;
int hours;
public:
//...
DateTime::DateTime(ifstream& archive); //reconstituting constructor
ofstream& Write(ofstream& archive);
ifstream& Read(ifstream& archive);
};
ofstream& DateTime::Write(ofstream& archive)
{
Date::Write(archive); //must invoke base class Write() first
archive.write( reinterpret_cast (&), sizeof(day));
archive.write( reinterpret_cast (&month), sizeof(month));
file:///D|/Cool Stuff/old/ftp/1/1/ch14/ch14.htm (9 von 18) [12.05.2000 14:46:48]
ANSI/ISO C++ Professional Programmer's Handbook - Chapter 14 - Concluding Remarks and Future Directions
archive.write( reinterpret_cast (&month), sizeof(year));
return archive;
}
ifstream& DateTime::Read(ifstream& archive)
{
Date::Read(archive);
archive.read( reinterpret_cast (&day), sizeof(day));
archive.read( reinterpret_cast (&month), sizeof(month));
archive.read( reinterpret_cast (&month), sizeof(year));
return archive;
}
DateTime::DateTime(ifstream& archive) //reconstituting constructor
{
Read(arcive);
}
Third Party Classes
Overriding the member functions Read() and Write() and serializing data members to and from a stream are
error prone and can cause maintenance difficulties. Whenever data members are added or removed, or when their
types are changed, the implementer has to modify these member functions accordingly -- but this is still managable.
However, deriving from classes that do not define a reconstituting constructor and the member functions Read()
and Write() is more difficult to handle because a derived class can only serialize its own members -- not members
of its base classes. The same difficulties exist with embedded objects. How are such subobjects serialized? It might
be possible to overcome these difficulties in some cases, albeit with considerable efforts. For example, a class that
contains a vector can iterate through the vector's members and serialize them one by one. This is only half the
story, though. A vector's state depends on other parameters, such as its capacity. Where can this information be
stored if the vector object itself cannot be serialized? Serializing arrays is another conundrum. One solution is to
write a header in the beginning of every serialized object that contains the number of elements. However, this won't
work with reference counted objects. Most implementations of std::string are reference counted, which means
that in the following code snippet, the five string objects share some of their data members:
#include
using namespace std;
void single_string()
{
string sarr[4];
string s = sarr[0];
for (int i = 1; i
{
sarr[i] = s;
}
}
Reference counting is an implementation detail that is hidden from the users of the class; it is impossible to query
the string object about how many strings it represents and to serialize this datum.
[ Pobierz całość w formacie PDF ]zanotowane.pldoc.pisz.plpdf.pisz.plkajaszek.htw.pl