Angelika Langer - Training & Consulting
HOME | COURSES | TALKS | ARTICLES | GENERICS | LAMBDAS | IOSTREAMS | ABOUT | NEWSLETTER | CONTACT |
 
HOME 

  OVERVIEW

  BY TOPIC
    JAVA
    C++

  BY COLUMN
    EFFECTIVE JAVA
    EFFECTIVE STDLIB

  BY MAGAZINE
    JAVA MAGAZIN
    JAVA SPEKTRUM
    JAVA WORLD
    JAVA SOLUTIONS
    JAVA PRO
    C++ REPORT
    CUJ
    OTHER
 

GENERICS 
LAMBDAS 
IOSTREAMS 
ABOUT 
NEWSLETTER 
CONTACT 
Deriving from IOStreams

Deriving from IOStreams
Deriving from IOStreams
Using the IOStreams Framework to Define Specialized Streams
 

C++ Report, September 1995
Klaus Kreft & Angelika Langer


 
 

Introduction.

One common way to make use of the IOStreams framework is by deriving from its classes in order to define specialized streams for special purposes. Such kind of user defined streams will usually be derived from the 'ios' class family, e.g. class 'istream' or 'ostream'. Very often it will be necessary to define a specialized stream buffer, too, which will be derived from class 'streambuf' or its descendants. (An example for this way of using IOStreams can be found in [1].)

However, these derivations are not completely trivial and there is a certain pitfall that may not be obvious to every IOStreams user. In this article we want to spend a few thoughts on where the pitfall actually is and take a deeper look at several ways to solve the problem. We will consider both derivation of a specialized stream and deriving a corresponding stream buffer to be used with the stream. Eventually we will address the forthcoming ANSI/ISO standard and show how to tackle the whole issue when using the standard IOStreams in the future.


Deriving a New Stream.

Let's start with the following approach. (Basically it is the kind of solution Cay Horstmann chose in his article.)

Approach 1.

The idea is to define a specialized stream buffer together with a specialized output stream. The user defined stream will use the user defined stream buffer as its buffer component:

class MyStreamBuf : public streambuf {
// ...
};

class MyOutputStream_1 : public ostream {
public:
MyOutputStream_1() : ostream(&msb),ios(0) {}
// ...
private:
MyStreamBuf msb;
// ...
};

On construction of 'MyOutputStream_1' the respective constructors will be executed as listed below:
ios(0)
ostream(&msb)
streambuf()
MyStreamBuf()
MyOutputStream_1()
Remark: In this list the constructors are ordered according to the instant of their completion, i.e. the constuctor which is completely executed first will be the first in this list. E.g. the constructor MyOutputStream_1() will be the last constructor to have accomplished its task, so it is the last one in this list. The idea behind this kind of ordering is that only after completion of a constructor the constructed object is ensured to be valid.

In analogy the destructors will be ordered by the instant when their execution starts, i.e. the moment when the object to be destroyed becomes invalid.

Considering the order of construction listed above it is visible that by the time ios() or ostream() are executed, the buffer component 'msb' will not yet be constructed. It follows that neither ios() nor ostream() must access the buffer.

In fact, the pointer handed over to the stream on its construction points to a still invalid object.

The same observation holds for destruction of a 'MyOutputStream_1'. Destructors are called in reverse order which means that neither ~ostream() nor ~ios() must access the stream buffer as it will already be destroyed.

The approach outlined above is a widely used solution in practice. Surprisingly enough it actually works with all currently available IOStreams implementations known to the authors.

This is possible because the IOStream implementations have constructors for class 'ios' and class 'ostream' that do not access the stream buffer at all.

The destructors of class 'ios' or class 'ostream' on the other hand do access the stream buffer in some IOStreams implementations. Nevertheless is works because the raw data of the 'MyOutputStream_1' object is still available when ~ios() and ~ostream() are executed and ~MyStreamBuffer() usually does not really invalidate its data.

Yet the approach seems to be hazardous because it relies on access to destroyed objects. Already tiny changes can break the whole code. Consider for example a change to MyStreamBuf so that it allocates data from the heap. On destruction of the buffer the heap data will probably be deleted which means a real invalidation as the storage management most likely will overwrite some data.

The use of the MyStreamBuf data member in ~ios() or ~ostream() will in this case cause an error if by chance the use includes access to the deleted heap data.

So what can we do? Is there another, more stable solution conceivable? Of course, there is.

Approach 2.

The idea is to allocate the stream buffer from the heap instead of using a data member of the stream object.

class MyStreamBuf : public streambuf {
// ...
};

class MyOutputStream_2 : public ostream {
public:
MyOutputStream_2() : ostream(new MyStreamBuf), ios(0) {};

~MyOutputStream_2() {
bp->sync();
delete bp;
bp = 0;
}
// ...
};

Just to remind readers to the innards of IOStreams: 'bp' is a protected member of class 'ios' which holds the pointer to the respective stream buffer. sync() is a virtual member function of class 'streambuf' which is responsible for cleanup activities.

On construction of 'MyOutputStream_2' the constructors will be executed as listed below:

ios(0)
streambuf()
MyStreamBuf()
ostream()
MyOutputStream_2()
This time ostream() receives a pointer to a valid, fully constructed stream buffer object.

Thanks to the "delete bp;" in ~MyOutputStream_2() destructors are called in the following order:

~MyOutputStream_2()
~MyStreamBuf()
~streambuf()
~ostream()
~ios()
Again neither ~ostream() nor ~ios() may access the stream buffer via 'bp' anymore. This time it would be really lethal as 'bp' is assured to point to invalid data. So, why does this work? It turns out that a buffer pointer that equals null has special semantics in some IOStreams implementations: It indicates that the stream buffer is not valid and the stream classes pay attention to this particular situation and do not access it if "bp == 0". (This explains why ~MyOutputStream_2() set "bp = 0;".)

Yet this is a solution that relies on peculiarities of the respective IOStream implementation and is not at all portable. AT&T's IOStreams has this undocumented 'feature', others may not have ...

Regarding portability ... The ANSI/ISO standard ensures that neither ~ios() nor ~ostream() will access the stream buffer on destruction. Hence "bp == 0" will not be necessary anymore. The whole problem evaporates in a sudden. See approach 4 below for further details.

But, we don't have a standard IOStream yet. So, is there a way to solve the problem in a stable AND portable way?

Approach 3.

What about providing the stream buffer via private inheritance rather than allocating it from the heap or using a data member of the stream object?

class MyStreamBuf : public streambuf {
// ...
};

class MyOutputStream_3 : virtual private MyStreamBuf, public ostream {
public:
MyOutputStream_3() : ostream((MyStreamBuf*) this), ios(0) {};
// ...
};

On construction of 'MyOutputStream_3' the constructors will be executed as listed below:

streambuf()
MyStreamBuf()
ios(0)
ostream()
MyOutputStream_3()

Note that this order of executing the constructors is due to the 'virtual' private derivation from streambuf.

See [2] ARM Section 12.6.2.: Virtual bases are constructed before any nonvirtual bases and in the order they appear on a depth-first left-to-right traversal of a directed acyclic graph of base classes; "left-to-right"

is the order of appearance of the base class names in the declaration of the derived class.

Obviously we have solved all problems, both on construction as well as on destruction: The stream buffer is constructed before any of the stream constructors is executed. As the destructors are called in reverse order the

corresponding is true for the destructors: The stream buffer is destroyed no sooner than all stream destructors have been executed.

Eventually we've found a stable and portable way to provide the stream buffer.

The downside of this approach is that it uses private virtual inheritance, which is no problem in itself. But it is conceptually strange. The virtual derivation in this case is necessary only to attain this particular order of construction/destruction, and for no other reason. What does the idiom of 'private virtual inheritance' mean ??? Certainly more than forcing the compiler to call destructors in a specific order.

Another philosophical remark about this solution: Private inheritance is frequently seen as conceptually equal to membership. This example proves it to be wrong: Membership, as used in approach 1, does not solve the problem, but private inheritance does!

Using the ANSI/ISO Standard IOStreams. (For the future.)

The ANSI/ISO standard will ensure that neither ~ios() nor ~istream()/~ostream() will access the stream buffer. The policy used by the IOStreams classes contained in the standard library is as follows:

Only those descendants from class 'ios' which really provide a stream buffer may access the stream buffer on construction and destruction, for purpose of calling sync() for example. (This affects classes like e.g. 'ofstream' and 'ifstream', as they provide a 'filebuf' object to be used as stream buffer.) All its base classes, which do not provide the stream buffer but make use of an externally provided buffer, must and will not touch the buffer on construction and destruction. (This concerns the classes 'ios', 'istream' and 'ostream'.)

What seems sensible and sound for the standard IOStreams classes will surely be good for most other IOStreams classes as well. We suggest to adopt this policy when deriving new classes from IOStreams. It fits neatly into the IOStreams framework and makes your new stream classes easy to comprehend.

Let's glance over the 3 solutions cosidered above. Will they still be sensible in the presence of the standard IOStreams?

Basically the problem was access to an already deleted stream buffer by one of the base classes' destructors for purpose of calling sync().

Now, when using the standard IOStreams, there will be no such problem any more. Neither ~ios() nor ~ostream() will access the already deleted stream buffer.

Following the general policy described above, the assignment of caring about synchronisation on destruction of a stream will be taken by the new stream class's destructor.

All three solutions make use of a specialized stream buffer. To make it a bit more exciting, let's say it overwrites sync():

class MyStreamBuf : public streambuf {
protected:
virtual int sync() {
// ... whatever is necessary for MyStreamBuf
}
};
Approach 1.
class MyOutputStream_1 : public ostream {
public:
MyOutputStream_1() : ostream(&msb),ios(0) {}
virtual ~MyOutputStream_1() { msb.pubsync(); }
// ...
private:
MyStreamBuf msb;
// ...
};
Remark: The function pubsync() is part of class streambuf's public interface and does no more than calling the private virtual sync() function.

Approach 2.

The previously necessary assignment 'sb = 0;' after having deleted the stream buffer is not needed anymore.

class MyStreamBuf : public streambuf {
// ...
};

class MyOutputStream_2 : public ostream {
public:
MyOutputStream_2() : ostream(new MyStreamBuf), ios(0) {};

~MyOutputStream_2() {
sb->pubsync();
delete sb;
}
// ...
};

Approach 3.

With this approach it was necessary to make the private streambuf base class a virtual base class in order to achieve a particular order of destructor calls. This is no longer necessary, so we can dispense with the virtual derivation and use ordinary private inheritance which is much more intuitive anyway.

class MyOutputStream_3 : private MyStreamBuf, public ostream {
public:
MyOutputStream_3() : ostream((MyStreamBuf*) this), ios(0) {};
virtual ~MyOutputStream_3() { sync(); }
// ...
};
Conclusion.

By and large, using the standardized IOStreams will lead to portable solutions in a much easier and more intuitive way.

We faced the situation that we wanted to derive a new stream class which 'has-a' new stream buffer. We considered three approaches to provide the stream buffer: as a data member of the stream class,

as a non-shared reference to a stream buffer on the heap and

by private inheritance.

With existing IOStream implementations there were subtle differences between the three approaches and we had to carefully pay attention to peculiarities of the various IOStream implementations. Hence, finding a portable solution was not trivial.

Quite the converese with the standard IOStreams. All three approaches intuitively yield a correct and portable solution. No further headache required. That's what a standard is for, isn't it?


Deriving a New Stream Buffer.

So far we have focused on deriving a new stream class and skillfully omitted all details about deriving the new stream buffer class. Will that be a similar hassle? Well, let's see ...

There is a certain analogy between deriving a new stream class and deriving a new stream buffer class: Both class families have a resource which can or must be provided externally. For the 'ios' class family this resource is the stream buffer. It has to be provided externally and a pointer to the stream buffer is handed over via an according constructor. For the 'streambuf' class family this resource is the underlying character buffer, which is nothing but an ordinary character array. It is usually allocated by the stream buffer itself. Still, there is the possibility to provide it externally and hand over a pointer to the external buffer via a call to the setbuf() function.

Given the latter situation we face an equivalent problem with stream buffers as we have discussed with streams: Do the 'streambuf' classes access the character buffer on construction or destruction? Construction is no issue as ther is no suitable 'streambuf' constructor which can take a pointer to the buffer as a parameter. You have to attach the external character buffer explicitly after construction by calling setbuf(). Fine! But what about destruction?

Let's go and look for solutions!

The only sensible reason for providing the character buffer externally we can conceive of is to have influence on the buffer size at runtime. (Surely one could contrive other reasons though.) Hence we will only consider solutions which allocate the character buffer dynamically at runtime from the heap.

Approach 1.

One can allocate the character buffer from the heap:

class MyStreamBuf_1 : public streambuf {
public:
MyStreamBuf_1(size_t s) : bfptr(new char[s])
{ setbuf(bfptr,s); };
virtual ~MyStreamBuf_1()
{ delete [] bfptr; }
private:
char* bfptr;
}

The order of destructor calls will be:

~MyStreamBuf_1()
~streambuf()

Again we face a problem here. We can't know what our IOStream implementation does on destruction of a stream buffer. It might chose to access its character buffer ... It follows, that this again is a non-portable approach.

Approach 2.

Another idea is to provide the character buffer via private inheritance:

class MyStreamBufResources {
public:
MyStreamBufResources(size_t s) : bfptr(new char[s])
{ }
~MyStreamBufResources()
{ delete [] bfptr; }
private:
char* bfptr;
}

class MyStreamBuf_2 : private MyStreamBufResources, public streambuf {
public:
MyStreamBuf_2(size_t s) : MyStreamBufResources(s)
{ setbuf(bfptr,s); }
// ...
}

The order of destruction will be:
~MyStreamBuf_2()
~streambuf()
~MyStreamBufResources()
Hence, whatever ~streambuf() choses to do to its character buffer we will have no problem as the buffer will still be "alive".

Using the ANSI/ISO Standard IOStreams. (For the future.)

At present it is not yet specified what streambuf::setbuf() in the standard IOStreams will be supposed to do. But there will still be a protected virtual setbuf() function and a public non-virtual pubsetbuf() function. So, for reasons of retaining compatibilty to existing IOStreams one shouldn't expect any dramatic changes.
 


Summary.

The problem discussed above is basically about providing a resource to a class, that itself only holds a pointer to the resource and accesses the resource via this pointer. As soon as the resource is provided externally, one has to ensure that that the resource is valid whenever the class decides to access the resource.

The really crucial point is access on construction and destruction as the resource might not yet or already be deleted.

A solution which always will work is wrapping the resource into a class and provide the resource via private derivation from the wrapper class.
 


References.

[1] Cay Horstmann. Extending the iostream library. C++ Report, May 1994

[2] M. Ellis & B. Stroustrup. The Annotated C++ Reference Manual, Addison-Wesley, 1990.
 
 
 
 

If you are interested to hear more about this and related topics you might want to check out the following seminar:
Seminar
 
Effective STL Programming - The Standard Template Library in Depth
4-day seminar (open enrollment and on-site)
IOStreams and Locales - Standard C++ IOStreams and Locales in Depth
5-day seminar (open enrollment and on-site)
 

 

  © Copyright 1995-2003 by Angelika Langer.  All Rights Reserved.    URL: < http://www.AngelikaLanger.com/Articles/C++Report/IOStreamsDerivation/IOStreamsDerivation.html  last update: 22 Oct 2003