Sie sind auf Seite 1von 104

Part1 Part2 Part3 Part4 Part5 Part6 Part7 Part8 Part9 Part10 Part11 Part12 Part13

Int
Part Part Part Part Part Part Part Part Part Part1 Part1 Part1 Part1
1 2 3 4 5 6 7 8 9 0 1 2 3

Classes
Last month we saw, among others, how we can give a struct well defined values by using constructors, and how C+
+ exceptions aid in error handling. This month we'll look at classes, a more careful study of object lifetime,
especially in the light of exceptions. The stack example from last month will be improved a fair bit too.

A class
The class is the C++ construct for encapsulation. Encapsulation means publishing an interface through which you
make things happen, and hiding the implementation and data necessary to do the job. A class is used to hide data,
and publish operations on the data, at the same time. Let's look at the "Range" example from last month, but this
time make it a class. The only operation that we allowed on the range last month was that of construction, and we
left the data visible for anyone to use or abuse. What operations do we want to allow for a Range class? I decide that
4 operations are desirable:
• Construction (same as last month.)
• find lower bound.
• find upper bound.
• ask if a value is within the range.
The second thing to ask when wishing for a function is (the first thing being what it's supposed to do) is in what
ways things can go wrong when calling them, and what to do when that happens. For the questions, I don't see how
anything can go wrong, so it's easy. We promise that the functions will not throw C++ exceptions by writing an
empty exception specifier.
I'll explain this class by simply writing the public interface of it:

struct BoundsError {};


class Range
{
public:
Range(int upper_bound = 0, int lower_bound = 0)
throw (BoundsError);
// Precondition: upper_bound >= lower_bound
// Postconditions:
// lower == upper_bound
// upper == upper_bound

int lowerBound() throw ();


int upperBound() throw ();
int includes(int aValue) throw ();
private:
// implementation details.
};
This means that a class named "Range" is declared to have a constructor, behaving exactly like the constructor for
the "Range" struct from last month, and three member functions (also often called methods,) called "lowerBound",
"upperBound" and "includes". The keyword "public," on the fourth line from the top, tells that the constructor and
the three member functions are reachable by anyone using instances of the Range class. The keyword "private" on
the 3rd line from the bottom, says that whatever comes after is a secret to anyone but the "Range" class itself. We'll
soon see more of that, but first an example (ignoring error handling) of how to use the "Range" class:

int main(void)
{
Range r(5);
cout << "r is a range from " << r.lowerBound() << " to "
<< r.upperBound() << endl;
int i;
for (;;)
{
cout << "Enter a value (0 to stop) :";
cin >> i;
if (i == 0)
break;
cout << endl << i << " is " << "with"
<< (r.includes(i) ? "in" : "out") << " the range"
<< endl;
}
return 0;
}
A test drive might look like this:

[d:\cppintro\lesson2]rexample.exe
r is a range from 0 to 5
Enter a value (0 to stop) :5

5 is within the range


Enter a value (0 to stop) :7

7 is without the range


Enter a value (0 to stop) :3

3 is within the range


Enter a value (0 to stop) :2

2 is within the range


Enter a value (0 to stop) :1

1 is within the range


Enter a value (0 to stop) :0
Does this seem understandable? The member functions "lowerBound", "upperBound" and "includes" are, and
behave just like, functions, that in some way are tied to instances of the class Range. You refer to them, just like you
do member variables in a struct, but since they're functions, you call them (by using the, in C++ lingo named,
function call operator "()".)
Now to look at the magic making this happen by filling in the private part, and writing the implementation:

struct BoundsError {};


class Range
{
public:
Range(int upper_bound = 0, int lower_bound = 0)
throw (BoundsError);
// Precondition: upper_bound >= lower_bound
// Postconditions:
// lower == upper_bound
// upper == upper_bound

int lowerBound() throw ();


int upperBound() throw ();
int includes(int aValue) throw ();
private:
int lower;
int upper;
};

Range::Range(int upper_bound, int lower_bound)


throw (BoundsError)
: lower(lower_bound), /***/
upper(upper_bound) /***/
{
// Preconditions.
if (upper_bound < lower_bound) throw BoundsError();
// Postconditions.
if (lower != lower_bound) throw BoundsError();
if (upper != upper_bound) throw BoundsError();
}

int Range::lowerBound() throw ()


{
return lower; /***/
}

int Range::upperBound() throw ()


{
return upper; /***/
}

int Range::includes(int aValue) throw ()


{
return aValue >= lower && aValue <= upper; /***/
}
First, you see that the constructor is identical to that of the struct from last month. This is no coincidence. It does the
same thing and constructors are constructors. You also see that "lowerBound", "upperBound" and "includes", look
just like normal functions, except for the "Range::" thing. It's the "Range::" that ties the function to the class called
Range, just like it is for the constructor.
The lines marked /***/ are a bit special. They make use of the member variables "lower_bound" and
"upper_bound." How does this work? To begin with, the member functions are tied to instances of the class, you
cannot call any of these member functions without having an instance to call them on, and the member functions
uses the member variables of that instance. Say for example we use two Range instances, like this:

Range r1(5,2);
Range r2(20,10);
Then r1.lowerBound() is 2, r1.upperBound() is 5, r2.lowerBound() is 10 and r2.upperBound() is 20.
So how come the member functions are allowed to use the member data, when it's declared private? Private, in C++,
means secret for anyone except whatever belongs to the class itself. In this case, it means it's secret to anyone using
the class, but the member functions belong to the class, so they can use it.
So, where is the advantage of doing this, compared to the struct from last month? Hiding data is always a good
thing. For example, if we, for whatever reason, find out that it's cleverer to represent ranges as the lower bound, plus
the number of valid values between the lower bound and upper bound, we can do this, without anyone knowing or
suffering from it. All we do is to change the private section of the class to:

private:
int lower_bound;
int nrOfValues;

And the implementation of the constructor to:

Range::Range(int upper_bound, int lower_bound)


throw (BoundsError)
: lower(lower_bound), /***/
nrOfValues(upper_bound-lower_bound) /***/
...

And finally the implementations of "upperBound" and "includes" to:

int Range::upperBound() throw ()


{
return lower+nrOfValues;
}

int Range::includes(int aValue) throw ()


{
return aValue >= lower && aValue <= lower+nrOfValues;
}
We also have another, and usually more important, benefit; a promise of integrity. Already with the struct, there was
a promise that the member variable "upper" would have a value greater than or equal to that of the member variable
"lower". How much was that promise worth with the struct? This much:

Range r(5, 2);


r.lower = 25; // Oops! Now r.lower > r.upper!!!
Try this with the class. It won't work. The only one allowed to make changes to the member variables are functions
belonging to the class, and those we can control.

Destructor
Just as you can control construction of an object by writing constructors, you can control destruction by writing a
destructor. A destructor is executed when an instance of an object dies, either by going out of scope, or when
removed from the heap with the delete operator. A destructor has the same name as the class, but prepended with the
~ character, and it never accepts any parameters. We can use this to write a simple trace class, that helps us find out
the life time of objects.

#include <iostream.h>

class Tracer
{
public:
Tracer(const char* tracestring = "too lazy, eh?");
~Tracer(); // destructor
private:
const char* string;
};

Tracer::Tracer(const char* tracestring)


: string(tracestring)
{
cout << "+ " << string << endl;
}

Tracer::~Tracer()
{
cout << "- " << string << endl;
}
What this simple class does is to write its own parameter string, prepended with a "+" character, when constructed,
and the same string, prepended by a "-" character, when destroyed. Let's toy with it!

int main(void)
{
Tracer t1("t1");
Tracer t2("t2");
Tracer t3;

for (unsigned u = 0; u < 3; ++u)


{
Tracer inLoop("inLoop");
}
Tracer* tp = 0;
{
Tracer t1("Local t1");
Tracer* t2 = new Tracer("leaky");
tp = new Tracer("on heap");
}
delete tp;
return 0;
}
When run, I get this behaviour (and so should you, unless you have a buggy compiler):
[d:\cppintro\lesson2]tracer.exe
+ t1
+ t2
+ too lazy, eh?
+ inLoop
- inLoop
+ inLoop
- inLoop
+ inLoop
- inLoop
+ Local t1
+ leaky
+ on heap
- Local t1
- on heap
- too lazy, eh?
- t2
- t1
What conclusions can be drawn from this? With one exception, the object on heap, objects are destroyed in the
reversed order of creation (have a careful look, it's true, and it's always true.) We also see that the object, instantiated
with the string "leaky" is never destroyed.
What happens with classes containing classes then? Must be tried, right?

class SuperTracer
{
public:
SuperTracer(const char* tracestring);
~SuperTracer();
private:
Tracer t;
};

SuperTracer::SuperTracer(const char* tracestring)


: t(tracestring)
{
cout << "SuperTracer(" << tracestring << ")" << endl;
}

SuperTracer::~SuperTracer()
{
cout << "~SuperTracer" << endl;
}

int main(void)
{
SuperTracer t1("t1");
SuperTracer t2("t2");
return 0;
}
What's your guess?

[d:\cppintro\lesson2]stracer.exe
+ t1
SuperTracer(t1)
+ t2
SuperTracer(t2)
~SuperTracer
- t2
~SuperTracer
- t1
This means that the contained object ("Tracer") within "SuperTracer" is constructed before the "SuperTracer" object
itself is. This is perhaps not very surprising, looking at how the constructor is written, with a call to the "Tracer"
class constructor in the initialiser list. Perhaps a bit surprising is the fact that the "SuperTracer" objects destructor is
called before that of the contained "Tracer", but there is a good reason for this. Superficially, the reason might
appear to be that of symmetry, destruction always in the reversed order of construction, but it's a bit deeper than that.
It's not unlikely that the member data is useful in some way to the destructor, and what if the member data is
destroyed when the destructor starts running? At best a destructor would then be totally worthless, but more likely,
we'd have serious problems properly destroying our no longer needed objects.
So, the curious wonders, what about C++ exceptions? Now here we get into an interesting subject indeed! Let's look
at two alternatives, one where the constructor of "SuperTracer" throws, and one where the destructor throws. We'll
control this by a second parameter, zero for throwing in the constructor, and non-zero for throwing in the destructor.
Here's the new "SuperTracer" along with an interesting "main" function.

class SuperTracer
{
public:
SuperTracer(int i, const char* tracestring)
throw (const char*);
~SuperTracer() throw (const char*);
private:
Tracer t;
int destructorThrow;
};

SuperTracer::SuperTracer(int i, const char* tracestring)


throw (const char*)
: t(tracestring),
destructorThrow(i)
{
cout << "SuperTracer(" << tracestring << ")" << endl;
if (!destructorThrow)
throw (const char*)"SuperTracer::SuperTracer";
}

SuperTracer::~SuperTracer() throw (const char*)


{
cout << "~SuperTracer" << endl;
if (destructorThrow)
throw (const char*)"SuperTracer::~SuperTracer";
}

int main(void)
{
try {
SuperTracer t1(0, "throw in constructor");
}
catch (const char* p)
{
cout << "Caught " << p << endl;
}
try {
SuperTracer t1(1, "throw in destructor");
}
catch (const char* p)
{
cout << "Caught " << p << endl;
}
try {
cout << "Let the fun begin" << endl;
SuperTracer t1(1, "throw in destructor");
SuperTracer t2(0, "throw in constructor");
}
catch (const char* p)
{
cout << "Caught " << p << endl;
}
return 0;
}
Here we can study different bugs in different compilers. Both GCC and VisualAge C++ have theirs. What bugs does
your compiler have? Here's the result when running with GCC. Comments about the bug found are below the result:

[d:\cppintro\lesson2]s2tracer.exe
+ throw in constructor
SuperTracer(throw in constructor)
- throw in constructor
Caught SuperTracer::SuperTracer
+ throw in destructor
SuperTracer(throw in destructor)
~SuperTracer
Caught SuperTracer::~SuperTracer
Let the fun begin
+ throw in destructor
SuperTracer(throw in destructor)
+ throw in constructor
SuperTracer(throw in constructor)
- throw in constructor
~SuperTracer

Abnormal program termination


core dumped
The first 4 lines tell that when an exception is thrown in a constructor, the destructor for all so far constructed
member variables are destructed, through a call to their destructor, but the destructor for the object itself is never
run. Why? Well, how do you destroy something that was never constructed? The next four lines reveal the GCC
bug. As can be seen, the exception is thrown in the destructor, however, the member Tracer variable is not destroyed
as it should be (VisualAge C++ handles this one correctly.) Next we see the interesting case. What happens here is
that an object is created that throws on destruction, and then an object is created that throws at once. This means that
the first object will be destroyed because an exception is in the air, and when destroyed it will throw another one.
The correct result can be seen in the execution above. Program execution must stop, at once, and this is done by a
call to the function "terminate". The bug in VisualAge C++ is that it destroys the contained Tracer object before
calling terminate.
What's the lesson learned from this? To begin with that it's difficult to find a compiler that correctly handles
exceptions thrown in destructors. More important, though, think *very* carefully, before allowing a destructor to
throw exceptions. After all, if you throw an exception because an exception is in the air, your program will terminate
very quickly. If you have a bleeding edge compiler, you can control this by calling the function
"uncaught_exception()" (which tells if an exception is in the air,) and from there decide what to do, but think
carefully about the consequences.

An improved stack
The stack from last month was in many ways better than a corresponding C implementation, but it was far from
adequate. An easy, C-ish way of improving it, is to implement it as an abstract data type, where functions push, pop,
and whatever's needed is available to the users. The C++ way is, not surprisingly, to write a stack class. Before
going into that, though, some thinking is needed regarding what the stack should do.
Minimum for a stack is functionality to push new elements onto it, and to pop the top element from it. The pop
function is a classical headache, because it both changes the state of the stack (removes the top element from it) and
returns whatever was the top element. This behaviour is dangerous in terms of errors, because you can easily lose
data. What if something fails while removing the top element? Should you return the top element value? If you do,
does that indicate that the it has been removed? It's better to make two functions of it, one that returns the top
element, and one that removes it. The one that removes it either returns or throws an exception (remember, either a
function fails, or does what it's supposed to do, there's no middle way. If it fails, it exits through an exception,
otherwise it returns.)
OK, so, we can see a class that, on the surface, looks something like this:

class intstack
{
public:
intstack(); // initialise empty stack
~intstack(); // free memory by popping all elements
void push(int aValue);
void pop(); // remove top element
int top(); // retrieve value of top element
private:
// implementation details
};
This looks fair. Normally copying and assignment (a = b) would be implemented too, but we'll wait with that until
next month, or this article will grow far too long. Now let's look at what can go wrong in the different operations.
• top. What if the stack is empty? It mustn't be.
• pop. Again, what if the stack is empty?
• push. Out of memory.
• construction. Nothing really.
• destruction. Tough one. If the stack is in a bad state, it might be indestructible.
Since top and pop requires that the stack isn't empty, we must allow the user to check if the stack is empty,
otherwise we don't leave them a chance, so another function is needed.
• isEmpty. I don't see how anything can go wrong in here.
So, with the problems identified, let's think about what to do when they occur.
• top and pop on empty stack, throw exception, stack remains empty.
• Out of memory on push. Throw exception and leave stack unchanged.
• invalid stack state in destruction? Can we find out of we have them? I don't think we can, without adding
significant control data, that probably increases the likelihood of exactly the kind of errors we want to
avoid. Thus, I *think* the best solution for this problem is to just be careful with the coding, and hope it
doesn't happen.
This leaves us with two different errors: Stack underflow (pop or top on empty stack), and out of memory.
We also found, rather easily, the preconditions for operations pop and top (!isEmpty().)
Now to think of post conditions. What's the post conditions for the different operations?
push(anInt): The stack can't be empty after that (post conditions always reflect successful completion, not failure.)
Also top() == anInt.
pop(): Currently no way to say, but let's change things a bit. Instead of having the method isEmpty() we add the
method nrOfElements(), then nrOfElements will be one less after pop.
top(): nrOfElements() same after as before.
Construction (from nothing): nrOfElements() == 0.
Destruction? Nothing. There's no object left to check the post condition on! We can state a post condition that all
memory allocated by the stack object is deallocated, but we can't check it (try to think of a method to do that, and
tell me if you find one.)
So, now we can write the public interface of the stack:

struct bad_alloc {}; // *1*


struct stack_underflow {};

class intstack
{
public:
intstack() throw ();
// Preconditions: -

~intstack() throw ();


// Preconditions: -
// Postconditions:
// The memory allocated by the object is deallocated

unsigned nrOfElements() throw ();


// Preconditions: -
// Postconditions:
// nrOfElements() == 0 || top() == old top() // *2*

void push(int anInt) throw (bad_alloc);


// Preconditions: -
// Postconditions:
// nrOfElements() > 0
// top() == anInt
// Behaviour on exception:
// Stack unchanged.

int top(void) throw (stack_underflow);


// Preconditions:
// nrOfElements() > 0
// Postconditions:
// nrOfElements() == old nrOfElements()
// Behaviour on exception:
// Stack unchanged.

void pop(void) throw (stack_underflow);


// Preconditions:
// nrOfElements() > 0
// Postconditions:
// nrOfElements() == 1 + old nrOfElements()
// Behaviour on exception:
// Stack unchanged.
private:
intstack& operator=(const intstack& is); // *3*
intstack(const intstack& is);

// implementation details
};
The promise to always leave the stack unchanged in when exceptions occur means that we must guarantee that
whatever internal data structures we're dealing with must always be destructible. This is tricky, but it can be done.
This requirement is also implied by our destructor guaranteeing not to throw anything.
*1*: the structs stack_underflow and bad_alloc are empty, we just throw them, and use the struct itself as the
information, nothing more is needed. For really new compilers, the new operator throws a pre-defined class called
bad_alloc. If you have such a compiler, remove the declaration of it above.
*2*: This looks odd, perhaps, but what this means is that if there are elements on the stack, the top elements must be
the same. Or literally as it says in the code comment, either the stack is empty, or the top elements are equal. You'll
get used to this reversed looking logic.
*3*: This is how the assignment operator looks like, if included, and below it, the copy constructor (constructing a
new stack by copying the contents of an old one.) I said we wouldn't implement these this month, and ironically that
is why they are declared private. The reason is that if you don't declare a copy constructor and assignment operator,
the C++ compiler will do it for you, and unfortunately, the compiler generated ones are usually not the ones you'd
want. I'll talk more about this next month. By declaring them private, however, coping and assignment is explicitly
illegal, so it's not a problem.
So, how do we implement this then? Why not like the one from last month, but with an additional element counter? I
think that's a perfectly reasonable approach. Here comes the complete class declaration, with the old
"stack_element" as a nested struct within the class.

struct bad_alloc {}; // *1*


struct stack_underflow {};
struct pc_error {}; // used for post condition violations.

class intstack
{
public:
intstack() throw ();
// Preconditions: -

~intstack() throw ();


// Preconditions: -
// Postconditions:
// The memory allocated by the object is deallocated

unsigned nrOfElements() throw (pc_error);


// Preconditions: -
// Postconditions:
// nrOfElements() == 0 || top() == old top()

void push(int anInt) throw (bad_alloc, pc_error);


// Preconditions: -
// Postconditions:
// nrOfElements() = 1 + old nrOfElements()
// top() == anInt
// Behaviour on exception:
// Stack unchanged.

int top(void) throw (stack_underflow, pc_error);


// Preconditions:
// nrOfElements() > 0
// Postconditions:
// nrOfElements() == old nrOfElements()
// Behaviour on exception:
// Stack unchanged.

void pop(void) throw (stack_underflow, pc_error);


// Preconditions:
// nrOfElements() > 0
// Postconditions:
// nrOfElements() + 1 == old nrOfElements()
// Behaviour on exception:
// Stack unchanged.
private:
intstack(const intstack& is); // hidden!!
intstack& operator=(const intstack& is); // hidden !!

struct stack_element
{
stack_element(int aValue, stack_element* p) throw ()
: value(aValue), pNext(p) {};
int value;
stack_element* pNext;
};
stack_element* pTop;
unsigned elements;
};
The only peculiarity here is that the constructor for the nested struct "stack_element" is defined in line (i.e. at the
point of declaration.) As a rule of thumb, this should be avoided, but it's OK for trivial member functions, like this
constructor, which only copies values.
So let's look at the implementation, bit by bit.

intstack::intstack() throw ()
: pTop(0),
elements(0)
{
// Preconditions: -
}

intstack::~intstack() throw ()
{
// Preconditions: -
// Postconditions:
// The memory allocated by the object is deallocated
while (pTop != 0)
{
stack_element* p = pTop->pNext;
delete pTop; // guaranteed not to throw.
pTop = p;
}
}
These are rather straight forward. The guarantee that "delete pTop" doesn't throw comes from the fact that the
destructor for "stack_element" can't throw (which is because we haven't written anything that can throw, and the
contents of "stack_element" itself can't throw since it's fundamental data types only.)

unsigned intstack::nrOfElements() throw (pc_error)


{
// Preconditions: -
return elements;

// Postconditions:
// nrOfElements() == 0 || top() == old top()

// no need to check anything with this


// implementation as it's trivially
// obvious that nothing will change.
}
Here I admit to being a bit lazy. Strictly speaking, the post condition should be checked, but since all that is done is
to return a value, it is obvious that the stack cannot change from this. I leave the post condition, and an explanation
for my laziness, as a comment, though, since it's valuable to others reading the sources. It's also valuable if, for some
reason, the implementation is changed so that it is not obvious. If that happens, the check should be implemented.

void intstack::push(int anInt) throw (bad_alloc, pc_error)


{
// Preconditions: -

unsigned old_nrOfElements = nrOfElements();


stack_element* pOld = pTop;

stack_element* pTmp = new stack_element(anInt, pTop);


if (pTmp == 0)
throw bad_alloc();

// the above either throws or succeeds. If it throws,


// the memory is deallocated and we're leaving the
// function with the exception (before assigning to
// pTop, so the stack remains unchanged.)

try {
pTop = pTmp;
++elements;

// Postconditions:
// nrOfElements() == 1 + old nrOfElements()
// top() == anInt

if (nrOfElements() != 1 + old_nrOfElements
|| top() != anInt)
{
throw pc_error();
}
}
catch (...) {
// Behaviour on exception:
// Stack unchanged.

delete pTop; // get rid of the new top element

pTop = pOld;
elements = old_nrOfElements;
throw;
}
}
This is not trivial, and also contains some news. Let's start from the beginning. "old_nrOfElements" is used both for
the post condition check that the number of elements after the push is increased by one, but also when restoring the
stack should an exception be thrown. The call to "nrOfElements" could throw "pc_error". If it does, the exception
passes "push" and to the caller since we're not catching it. This is harmless since we haven't done anything to the
stack yet. On the next line we store the top of stack as it was before the push. This is used solely for restoring the
stack in the case of exceptions. This assignment cannot throw since "pOld" and "pTop" are fundamental types
(pointers). On the next line a new stack element is created on the heap. Here there are three possibilities. Either the
creation succeeds as expected, in which case everything is fine, or we're out of memory (the only possible error
cause here since the constructor for "stack_element" cannot throw.) For most of you, an out of memory situation
will mean that the return value stored in "pTmp" is 0. That case is taken care of on the next two lines.
If you have a brand new compiler, on the other hand, operator new itself throws "bad_alloc" when we're out of
memory. If you have such a compiler, it'll most probably complain about the next two lines. If so, just remove them,
since they're unnecessary in that case. OK, either case, if we're out of memory here, "bad_alloc" will be thrown and
the stack will be unchanged. Next we start doing things that changes the stack, and since we promise the stack won't
be changed in the case of exceptions, things that do change the stack goes into a "try" block. Setting the new stack
top and incrementing the element counter is not hard to understand.
The post condition check is interesting, though. Here we have three situations in which an exception results. The call
to "nrOfElements" may throw, the call to "top" may throw, and the post condition check itself might fail, in which
case we throw ourselves. All these three situations are handled in the catch block. "catch (...)" will catch anything
thrown from within the try block above. What we do when catching something, is to free the just allocated memory
(which won't throw for the same reason as for the destructor.) We also restore the old stack top and the element
counter. Thus the stack is restored to the state it had before entering "push", without having leaked memory. Then,
what we must do, is to pass the error on to the caller of "push", and that is what the empty "throw;" does. An empty
"throw;" means to re throw whatever it was that was caught. A throw like this is only legal within a catch block (use
it elsewhere and see your program terminate rather quickly.)

int intstack::top(void) throw (stack_underflow, pc_error)


{
// Preconditions:
// nrOfElements() > 0

if (nrOfElements() == 0 || pTop == 0)
{
throw stack_underflow();
}

return pTop->value;

// Postconditions:
// nrOfElements() == old nrOfElements()

// No need to check with this implementation!


}
This is not so difficult. If we have no elements on the stack, we throw, otherwise return the top value. As with
"nrOfElements", I'm lazy with the post condition check, but careful to document the behaviour should the
implementation for some reason change into something less obvious.

void intstack::pop(void) throw (stack_underflow, pc_error)


{
// Preconditions:
// nrOfElements() > 0

if (nrOfElements() == 0 || pTop == 0)
{
throw stack_underflow();
}

unsigned old_elements = nrOfElements();


stack_element* pOld = pTop;
try {
pTop = pTop->pNext;
--elements;

// Postconditions:
// nrOfElements() + 1 == old nrOfElements()

if (nrOfElements() + 1 != old_elements)
{
// Behaviour on exception:
// Stack unchanged.

throw pc_error();
}
}
catch (...) {
elements = old_elements;
pTop = pOld;
throw;
}
delete pOld; // guaranteed not to throw.
}
The exception protection of "pop" works almost exactly the same way as with "push". The thing worth mentioning
here, though, is why "delete pOld" is located after the "catch" block and not within the "try" block. Suppose the
deletion did, despite its promise, throw something. If it did, it would be caught, and the top of stack would be left to
point to something undetermined. As it is now, if it breaks its promise, we too break our promise not to alter the
stack when leaving on exception, but we at least make sure the stack is in a usable (and most notably, destructible)
state.
After having spent this much time on writing this class, it's time to have a little fun and play with it, don't you think?

#include <iostream.h>

int main(void)
{
try {
cout << "Constructing empty stack is1" << endl;

intstack is1;
cout << "is1.nrOfElements() = "
<< is1.nrOfElements() << endl;

cout << "is1.push(5)" << endl;


is1.push(5);
cout << "is1.top() = " << is1.top() << endl;
cout << "is1.push(32)" << endl;
is1.push(32);
cout << "is1.top() = " << is1.top() << endl;
cout << "is1.nrOfElements() = "
<< is1.nrOfElements() << endl;

cout << "is1.pop()" << endl;


is1.pop();
cout << "is1.nrOfElements() = "
<< is1.nrOfElements() << endl;
cout << "is1.top() = " << is1.top() << endl;

cout << "is1.pop()" << endl;


is1.pop();
cout << "is1.nrOfElements() = "
<< is1.nrOfElements() << endl;
} catch (bad_alloc&) {
cout << "Out of memory" << endl;
} catch (stack_underflow&) {
cout << "Stack underflow" << endl;
} catch (pc_error&) {
cout << "Post condition violation" << endl;
}
return 0;
}
I'm staying within the limits of the allowed here, but please make changes to the test program, and the stack
implementation, to break the rules and see what happens. It should either work, or say why it fails. Um, yes, on the
catch clauses I don't bind the exception instance caught to any named parameter. The reason is simply that I don't
use it. The knowledge that something of that type has been caught is, in this case, enough.
Now I will break a promise from last month. I won't go into more details with references. That'll be dealt with later,
because this is where I end this month's lesson.

Exercise
1. Something that is badly missing in the stack implementation above, is a good check for the integrity of the
stack object itself. For example, what if we somehow manage to get "elements" to non-zero, while "pTop"
is 0? That's a terrible error that must not occur, and if it does, it must not go undetected. What I'd like you
to do, is to see what kind of "internal state" tests that can be done, and to implement them. Please discuss
your ideas with me over e-mail (this month, if I take a long time in responding, please don't feel ignored.
I'll be net-less most of August.)
2. It's generally considered to be a bad idea to have public data in a class. Can you think of why? Mail me
your reasons.

Recap
Again a month filled with news.
• You have seen how classes can be used to encapsulate internals and publish interfaces with the aid of the
access specifiers "public:" and "private:"
• Member functions are always called together with instances (objects) of the class, and thus always have
access to the member data of the class.
• A member function can access private parts of a class.
• Destruction of objects is done in the reversed order of construction, except when the objects are allocated
on the heap, in which case they're destroyed when the delete operator is called for a pointer to them.
• We have seen that throwing exceptions in destructors can be lethal. (This is not to say that it should never
ever be done, but that a lot of thought is required before doing so, to ensure that the program won't die all
of a sudden.)
• You can now iterate your way to a good design by thinking of 1. What the function should do. 2. What can
go wrong. 3. What should happen when something goes wrong. 4. How can a user of the class prevent
things from going wrong. When you have satisfactory answers to all four questions for all functionality of
your class, you have a safe design.
• You have seen how it is possible to, by carefully crafting your code, make your member functions
"exception safe" without being bloated with too many special cases ( "catch(...)" and "throw;" helps
considerably here.)

Next
Next month there will most probably be a break, since I'll be on a well needed vacation. After that, however, we'll
have a look at copy construction and assignment (together with a C++ idiom often referred to as the "orthodox
canonical form.") I promise to explain the references in more detail too.
Please, by the way, I need your constant feedback. Write me! I want opinions and questions. If you think I'm wrong
about things, going to fast, too slow, teaching the wrong things, whatever; tell me, ask me.

Part Part Part Part Part Part Part Part Part Part1 Part1 Part1 Part1
1 2 3 4 5 6 7 8 9 0 1 2 3
[NOTE: Here is a link to a zip of the source code for this article. Ed.]
So far we've covered error handling through exceptions, and encapsulation with classes. The feedback from part 2
tells me I forgot a rather fundamental thing; what exactly is encapsulation, what should we make classes of. What's
the meaning of a class? I will get to this, but first let's finally have a look at the promised references.

References
C++ introduces an indirect kind of type that C does not have, the reference. A reference is in itself not a type, it
always is a reference of some type, just like arrays are arrays of something and pointers are pointers to something.
A reference is a means of indirection. It's a way of reaching another variable. This may sound a lot like a pointer, but
don't confuse the two, they're very different. See a reference more as an alias for another variable. Some details
about references:
• References must be initialized to refer to something. There is no such thing as a 0 reference.
• Once bound to a variable there is no way to make the reference refer to something else.
• There is no such thing as "reference arithmetic."
• You cannot get the address of a reference. You can try to, but what you get is the address of the variable
referred to.
References are denoted with an unary "&", just the same ways as pointers are denoted with an unary "*". Let's have
a look at an example:

int main(void)
{
int i = 0;
int& x; // error, would be an unbound reference.
int& r = i; // r now refers to i.
++r; // now i == 1, r still refers to i.
if (&r != &i)
throw "Broken compiler";
return 0;
}
From this, one may wonder, what on earth are references for? Why would anyone want them? Well, for one, they
offer a certain security over pointers; it's so easy to get a pointer referring to something that doesn't exist, or
something else than the intended. They're also handy as a short-cut into long nested structs" and arrays. Here's an
example:

struct A {
int b[5];
int x;
char d;
};

struct C {
A* p[10];
int q;
};

C* pc;

// and somewhere else, pc is given a value and is


// here used.

A& ra = pc->p[2];
ra.b[3]=5; // pc->p[2]->b[3] = 5;
ra.b[4]=2; // pc->p[2]->b[4] = 2;
The reference in this case just makes life easier.
In parts 1 and 2, I used references when catching exceptions. References are also often used for parameters to
functions. If we look at the exceptions, it means that instead of getting a local copy of the thing thrown, we get a
reference to the thing thrown, and we can manipulate it if we want to, instead of manipulating our own copy. The
same goes for parameters to functions. Passing an object by reference instead of by value, can some times be
necessary, and sometimes beneficial in terms of performance. The reason for the performance benefit is that the
when passing a parameter by value, the object is copied; the function uses a local object of its own, that is identical
to the one you passed. If copying the object is an expensive operation, which in some cases it is, then passing by
reference is cheaper. However, passing parameters by reference can be dangerous. When you do, the function has
access to the very object you pass, and if the function modifies it, the caller better be prepared for that. A commonly
used way around this is to declare the parameter as a "const" reference. This means that you get a reference, as
before, but the reference is treated as was it a constant, and because of this all attempts to change its value will cause
a compile time error.
Here's an example of passing a parameter by "const" reference. It uses the "intstack" from the previous lesson:

// put the declaration of intstack here...


void workWithStack(const intstack& is)
{
// work with is
is.pop(); // Error, attempting to alter
// const reference.
}

int main(void)
{
intstack i;
i.push(5);
workWithStack(i);
return 0;
}
Since the "intstack" class does not have a copy constructor (it was declared private, remember?) it is impossible to
pass instances of it to functions in other ways than by reference (or by pointer.)
There are situations when a reference is dangerous, though. One such trap, that I think all C++ programmers fall into
at least once, is returning a reference to a local variable. Have a look at this:

#include <iostream.h>

int& ir(void) // function returning reference to int


{
int i = 5;
return i;
}

int main(void)
{
cout << ir() << endl;
return 0;
}
What will this program print? It's hard to tell. It could be anything, if it prints at all. It might just crash. Why? The
function "ir" returns a reference to an "int", that the "main" function prints. So far so good, but what does the
reference returned refer to? It refers to the local variable "i" in "ir". If you remember the "tracer" examples from the
previous lesson, you remember that the variable ceases to exist when exiting the function. In other words, the
reference returned refers to a variable that no longer exists! Don't do this! Or rather, do it now, at once, just to have
your one time mistake over with :-)

What's a class?
Now for the theoretical biggie. What, exactly, is the meaning of a class. When should you write a class, what should
the class allow you to do, and what's a good name for a class? What's the relation between classes and objects?
When you write programs in Object Oriented Programming Languages, be it C++, Objective-C, SmallTalk, Eiffel,
Modula-3, Java or whatever, you write classes. A class is, as I mentioned in part 2, a method of encapsulation, but
more importantly, a class is a type. When you define a class, you add a new type to the language. C++ comes with a
set of built in types like "int", "unsigned" and "double". In the previous lesson, when we wrote the class "intstack",
we introduced a new type to the language, which programs could use, the stack of integers. The member functions
of the class, describe the semantics of the type. With the built in integral types, we have operations like adding two
instances of the type, yielding a third instance, which value happens to be the sum of the values of the other two. We
can increment the value of instances of the type with operations like ++, and so on. With the "intstack", we had the
operations "pop", "top", "push" and "nrOfElements", in addition to well defined construction and destruction of
instances.
So, how can you know what classes to make? Classes are, as a rule of thumb, descriptions of ideas. "Bicycle" for
example, is a classic example of a class. The idea "Bicycle" that is, not my particular bicycle. My bicycle is a
physical entity that is currently getting wet in the rain. The idea of bicycle is a very good candidate for a class. What
my bicycle is, on the other hand, is a good candidate for an instance of the class "Bicycle." So, when thinking of the
problem you want to solve, you might have a good candidate for a class X, if you can say "The X ...", "An X...", or
"A kind of X...". The objects are the instances of types (yes, an instance of type "float" is also an object, they need
not be instances of classes.) A class represent the idea, and the functions that represent the semantics. Usually
instances of the class has a state (for example, the state of a stack is the elements in it, and their order.) Having state
means that the same member function can give different results depending on what has been done to the object
before calling the member function (again, with a stack, the value returned by "top()" or "nrOrElements()" depends
on the history of "push()" and "pop()" calls.) The class has member data to represent state. There are, however,
exceptions to this rule of thumb. For example, is a mathematical function a class that you'd like to have instances of
to toy with in your program? According to the rule, it is not, since a mathematical function is state less. In most
situations, the answer would, as expected, be no, but if you design a program for use by electronics engineers when
designing their gadgets, you better have amplifiers (multiplication,) adders, subtractors and so on, or they won't use
your program.
Note that objects don't exist when you write your program. Objects are run-time entities. When you write your
program, what exists are types, descriptions of how instances of types can be used, and descriptions of semantics
and state representation. When your program executes, the identifiers, (like "pc" in the reference example above) are
replaced by bit-patterns representing objects.
So, then, what member functions should a class have? This is even harder to say, because there are so many ways to
solve every problem. However, the things that you need to do, when solving your problem, to instances of types,
like "Bicycle" or "intstack", must in one way or the other be expressible through the classes. If I need to ride my
bicycle, it can be that the class "Bicycle", should have the member function "beRiddenBy" accepting an instance of
class "Human", but it might also be that class "Human" should have the member function "ride" accepting an
instance of class "Bicycle" as its parameter. If the starting point or destination are important, they probably should
be parameters to the member functions. If the road itself is important, you probably need a class "Road", which you
want to pass an instance of to the member function of either "Bicycle::beRiddenBy" or "Human::ride".
Given this, you might start to feel like someone's been fooling you. This Object Oriented Programming thing is a
hoax! What it's all about, is class oriented programming. The objects are, after all, just the run time instances of the
classes.

The Orthodox Canonical Form


The basic operations you should, in general, be able to do with objects of any class is construction from scratch,
construction by copying another instance, assignment and destruction. This places a slightly heavier burden on us,
compared to the work with the "intstack." The "intstack" guaranteed that no matter what happened, an instance was
always destructible. The Orthodox Canonical Form poses the additional requirement that an instance must always be
copyable. Normally this extra burden is light, but there are tricky cases. Construction from scratch we've seen.
Construction by copying is done by the copy constructor.
Given a class named C, the copy constructor looks like this:

class C
{
public:
C(const C& c); // copy constructor
// other necessary member functions.
};
The job of the copy constructor is to create an object that is identical to another object. It is your job to make sure it
does this. This does not mean that every member variable of the newly constructed object must have values identical
to the ones in the original. On the contrary, they often differ. What's important, though, is that they're semantically
identical (i.e. given the same input to member functions, they give the same response.) The "intstack" for example
must make its own copy of the stack representation in the copy constructor. This means that the base pointer will
differ, but as far as you can see through the "push", "pop" and "top" member functions, there is no difference
between the copy and the original.
Next in line is copy assignment. Again, given a class C, the copy assignment operator looks like this:

class C
{
public:
C& operator=(const C&);
// other necessary member functions.
};
Writing the copy assignment operator is more difficult than writing the copy constructor. Not only does the copy
assignment operator need to make the object equal to its parameter, it also needs to cleanly get rid of whatever
resources it might have held when being called (The copy constructor does not have this problem since it creates a
new object that cannot have held any data since before.) The return value of an assignment operator is (by tradition,
not by necessity) a reference to the object just assigned to. When inside a member function (the assignment operator
as defined above is a member function) the object can be reached through a pointer named "this," which is a pointer
to the class type. For the class C, above, the type of "this" is "C* const" This means that is's a pointer to type C, and
the pointer itself is a constant (i.e. you cannot make "this" point to anything else than the current instance.) The
reference to the object is obtained by dereferencing the "this" pointer, so the last statement of an assignment operator
is almost always "return *this;"
The difficulty of writing a good copy constructor and copy assignment operator is best shown through a classical
error:

class bad
{
public:
bad(void); // default constructor
bad(const bad&); // copy constructor
~bad(void); // destructor
bad& operator=(const bad&); // copy assignment
private:
int* pi;
};

bad::bad(void)
: pi(new int(5)) // allocate new int on heap and
// give it the value 5.
{
}

bad::bad(const bad& b)
: pi(b.pi) // initialize pi with the value of b's pi
{ // This is very bad, as you will soon see
}

bad::~bad(void)
{
delete pi;
}

bad& bad::operator=(const bad& b)


{
pi = b.pi; // This seamingly logical and simple
return *this; // assignment is also disasterous.
}

int main(void)
{
bad b1;
{
bad b2(b1); // b2.pi is now the same as b1.pi.
} // Here b2 is destroyed, and b2's destructor is
// called. This means that the memory area
// pointed to by b2.pi (and hence also b1.pi) is
// no longer valid

bad b3(b1); // Make b3.pi point to the same invalid


// memory area!
bad b4;
bad b5;
b5 = b4; // The memory allocated by b5 was never
// deallocated. We have a memory leak!
return 0;
} // The destrctor of b1 and b3 attempt to deallocate
// the memory already dealloceted by the destructor
// of b2. The destructors of b4 and b5 both attempt
// to deallocate the same memory (b5 first,
// correctly so, and then b4, which deallocates
// already deallocated memory.
OK, so from the example it is pretty clear that it's more work than this. The copy constructor should allocate its own
memory, and initialise that memory with the same value as that pointed to by the original. This goes for the copy
assignment operator too, but it also needs to discard the pointer it already had. By doing so, we guarantee that the
pointers owned by the objects are truly theirs, and their destructor can safely deallocate them. We do, however, have
yet a problem to deal with, that of self assignment. A version of the program fixing the above issues can show you
what is meant by that:

// class declaration, default constructor and


// destructor are identical and because of that not
// shown here.

bad::bad(const bad& b)
: pi(new int(*b.pi)) // initialize pi as a new int
// with the value of b's pi
{ // This guarantees that both the new object and the
} // original are destructible.

bad& bad::operator=(const bad& b)


{
delete pi; // No more memory leak
pi = new int(*b.pi); // Get a new pointer and
// initialise just as in
return *this; // the copy constructor.
} // Can you spot the problem with this one?

int main(void)
{
bad b1;
{
bad b2(b1); // b2.pi now points to its own area.
} // Here b2 is destroyed, and b2's destructor is
// called. This means that the memory area
// pointed to by b2.pi is no longer valid
// b1.pi is still valid, though.

bad b3; // Allocate new memory


b3=b1; // Deallocate, and allocate new again

b3=b3; // Whoa!! b3.pi is first deallocated, then


// b3.pi is allocated again and initialised
// with the value no longer available!!!
return 0; // all OK, all objects refer to their own
// memory, so deallocation is not a
// problem.
}
OK, so assigning an object to itself is perhaps not the most frequently done operation in a program, but that doesn't
mean it's allowed to crash, right? So, how can we make the copy assignment operator safe from self assignment?
Here are two alternatives:

bad& bad::operator=(const bad& b)


{
if (pi != b.pi)
{
delete pi;
pi = new int(*b.pi);
}
return *this;
}

bad& bad::operator=(const bad& b)


{
if (this != &b)
{
delete pi;
pi = new int(*b.pi);
}
return *this;
}
Common to both is that they check if the right hand side (parameter b) is the same object. If it is, the assignment is
simply not done. The first alternative does this by comparing the "pi" pointer. The second by comparing the pointer
to the objects themselves. The latter perhaps feels a bit harder to understand, but it's actually the one most frequently
seen, because normally classes have more than one member variable to check for. Note that if your class only has
member variables of types for which copying the values does not lead to problems, the tests above are not necessary.
With these changes done, the class deserves a name change. It is no longer bad.
In the previous lesson, the copy constructor and copy assignment operator was declared private, to prevent copying
and assignment. The reason is that a C++ compiler automatically generates a copy constructor and copy assignment
operator for you if you don't declare them. The auto-generated copy constructor and assignment operator, however,
will just copy/assign the member variables, one by one. In some cases this is perfectly OK. The "Range" class from
the previous lesson, for example, does fine with this auto-generated copy constructor and copy assignment operator.
The "intstack" on the other hand does not, since then both the original and the copy would share the same
representation (and have exactly the same problem as described in the above "bad" example!)
If you decide that for your class, the auto generated copy constructor and/or copy assignment operator is OK, leave a
comment in the class declaration saying so, so that readers of the source code know what you're thinking. Otherwise
they might easily think you've simply forgotten to write them.
One last thing before wrapping up...

Const Correctness
When talking about passing parameters to functions by reference, I mentioned the const reference as a way to ensure
that the parameter won't get modified, since the const reference treats whatever it refers to as a constant and thus
won't allow you to do things that would modify it. The question is, how does the compiler know if something you do
to an object will modify it? Does "pop" modify the "intstack?" Yes, it does. It removes the top element. Does "top"
modify the stack? No. So, it should be allowed to call "top" for a constant stack, right? The problem is that the
compiler doesn't know which member functions modify the objects, and which don't (and assumes they do, just to
be on the safe side) unless you tell it differently. Since, by default, a member function is assumed to alter the object,
you are, by default, not allowed to do anything at all to a constant object. This is of course hard. Fortunately we can
tell the compiler differently. We can change "top" to be declared as follows:

class intstack {
public:
// misc member functions
int top(void) const throw(stack_underflow,pc_error);
// misc other member functions
};
It's the word "const" after the parameter list that tells the compiler that this member function will not modify the
object and can safely be called for constant objects. As a matter of fact, now when we know about references, we
can do even better by writing two member functions "top", one "const" and one not, with the non-const version
returning a non-const reference to the element instead. This has a tremendous advantage: For constant stack objects,
we can get the value of the top element, for non-constant stack objects, we can alter the value of the top element by
writing like this:

intstack is;
is.push(5); // top is now 5;
is.top() = 3; // change value of top element!
There is no magic involved in this. Just as I mentioned in part one, functions can be overloaded if their parameter list
differs. Member functions can be overloaded on "constness." The "const" member function is called for constant
objects (or, const references or pointers, since they both treat the object referred to as if it was a constant.) The non-
const member function is called for non-constant objects. Note that it is only member functions you can do this
"const" overloading on. You cannot declare non-member functions "const." Our overloaded "top" member functions
can be declared like this:

class intstack {
public:
// misc member functions
int top(void) const throw(stack_underflow,pc_error);
int& top(void) throw (stach_underflow,pc_error);
// misc other member functions
};
This is getting too much without concrete examples. Here's a version of "intstack" with copy constructor, copy
assignment operator, const version of "top" and "nrOfElements", and a non-const version of "top" (just as above.)
Only the new and changed functions are included here. You'll find a zip file with the complete sources at the top.

class intstack
{
public:
// the previous memberfunctions

intstack(const intstack& is) throw (bad_alloc);


// Preconditions: -

intstack& operator=(const intstack& is)


throw (bad_alloc);
// Preconditions: -

unsigned nrOfElements() const throw (pc_error);


// Preconditions: -
// Postconditions:
// nrOfElements() == 0 || top() == old top()

int& top(void) throw (stack_underflow, pc_error);


// Preconditions:
// nrOfElements() > 0
// Postconditions:
// nrOfElements() == old nrOfElements()
// Behaviour on exception:
// Stack unchanged.

int top(void) const throw(stack_underflow,pc_error);


// Preconditions:
// nrOfElements() > 0
// Postconditions:
// nrOfElements() == old nrOfElements()
// Behaviour on exception:
// Stack unchanged.

private:
// helper functions for copy constructor, copy
// assignment and destructor.

stack_element* copy(void) const throw (bad_alloc);


void destroyAll(void) throw();
};
Since copying elements of a stack is the same when doing copy assignment and copy construction, I have a private
helper function that does the job. This is not necessary by any means, but it means I won't have identical code in two
places, and that is usually desirable. After all, if ever you need to change the code, you can bet you'll forget to
update one of them otherwise, and you have a subtle bug that may be hard to find. With only one place to update,
that mistake is hard to make. The same goes for deallocation of the stack. It is needed both in copy assignment and
destructor. Since these helper functions "copy" and "destroyAll" are purely intended as an aid when implementing
copy assignment, copy constructor and destructor, they're declared private. Just as a private member variable can
only be accessed from the member functions of a class, and not by anyone else, member functions declared private
can only be accessed from member functions of the same class. They have nothing what so ever to do with how the
stack works, just how it's implemented.
Here comes the new implementation of "nrOfElements." Can you see what's different from the previous lesson?

unsigned
intstack::nrOfElements() const throw (pc_error)
{
// Preconditions: -
return elements;
// Postconditions:
// nrOfElements() == 0 || top() == old top()
// no need to check anything with this
// implementation as it's trivially
// obvious that nothing will change.
}
There isn't anything at all that differs from the previous version of "nrOfElements", other than that it's declared to be
"const." Had we, in this member function (or any other member function declared as "const" attempted to modify
any member variable, the compiler would give an error, saying that we're attempting to break our promise not to
modify the object. "const" methods are thus good also as a way of preventing you from making mistakes. Note that
declaring a member function "const" does not mean it's only for constant objects, it just means that it's callable on
constant objects too. Whenever you have a member function that does not modify any member variable, declare it
"const" so that errors can be caught by the compiler. It saves you debug time, in addition to making those member
functions callable for constant objects (or constant references or pointers.)
Next in turn is "top", or rather the two versions of "top":

int intstack::top(void) const


throw (stack_underflow, pc_error)
{
// Preconditions:
// nrOfElements() > 0
if (nrOfElements() == 0 || pTop == 0)
{
throw stack_underflow();
}
return pTop->value;
// Postconditions:
// nrOfElements() == old nrOfElements()
// No need to check with this implementation!
}

int& intstack::top(void)
throw (stack_underflow, pc_error)
{
// Preconditions:
// nrOfElements() > 0
if (nrOfElements() == 0 || pTop == 0)
{
throw stack_underflow();
}
return pTop->value;
// Postconditions:
// nrOfElements() == old nrOfElements()
// No need to check with this implementation!
}
As can be seen, not much differs between the two variants of "top." The implementation is in fact identical for both,
but the first one returns a value and is declared const, the other one is not declared const and returns a reference. So
why do we have two identical implementations here, when I earlier mentioned that this is always undesirable? The
reason is simply that although the implementation is identical, neither can be expressed in terms of the other. The
non-const version cannot be implemented with the aid of the const version, since we'd then return a reference to a
local value. This is always bad, does not have the desired effect, and quite likely to cause unpredictable run-time
behaviour. The "const" version could be implemented in terms of the non-const version, if it wasn't for the fact that
it is not declared "const." The implementation of a const member function is not allowed to alter the object, and is,
as a consequence of this, not allowed to call non-const member functions for the same object.
Remember that a reference really isn't an object on its own? You cannot distinguish it in any way from the object it
refers to. In this case it means that what's returned from the non-const version of "top" is the top element itself, not a
local copy of it. Since it is the element itself, it can be modified. Note that there is a danger in this too: What about
this example?

intstack is;
is.push(45);
int& i=is.top(); // i now refers to the top element
i=32; // modify top element.
int val=is.top(); // val is 32.
is.pop(); // what does i refer to now?
i=45; // what happens here?
The answer to the last two questions is that "i" refers to a variable that no longer exists and that when assigning to it,
or getting a value from it, anything can happen. If you're lucky, your program will crash right away, if you're out of
luck, it'll start behaving randomly erratically!
Now for the copy constructor. With the help of the "copy" member function, it's really simple!

intstack::intstack(const intstack& i) throw (bad_alloc)


: pTop(i.copy()),
elements(i.elements)
{
// Preconditions: -
// Postconditions:
}
The "pTop" member of the instance being created is initialized with the value from "i.copy()". The "copy" helper
function, creates a new copy of i's representation ("pTop" and whatever it points to) on the heap and returns the
pointer to its base. If "i" is an empty stack, "copy" returns 0. If we run out of memory when "copy" is working,
whatever was allocated will be deallocated, and "bad_alloc" thrown. In this case, it means that "bad_alloc" will be
thrown before "pTop" is initialized, and thus the new object will never be constructed.
The copy assignment operator is a little bit trickier, but not that bad.

intstack& intstack::operator=(const intstack& i)


throw (bad_alloc)
{
if (this != &i)
{
stack_element* pTmp = i.copy();
// can throw bad_alloc

destroyAll(); // guaranteed not to throw!


pTop=pTmp;
elements=i.elements;
}
return *this;
}
Seemingly simple, and yet both efficient and exception safe. The difficulty lies in being careful with the order in
which to do things. Here a temporary pointer "pTmp" is first set to refer to the copy of "i's" representation. This is
very important from an exception handling point of view. Suppose we first destroyed the contents and then tried to
get a copy, but the copying threw "bad_alloc." Since we're not catching "bad_alloc", it flows out of the function as
intended, but our own "pTop" would point to something illegal, and thus our promise to always stay destructible,
and copyable whenever resources allow, would be broken. Instead, first getting the copy is essential. If the copying
fails, the member variables are not altered, and the object remains unchanged (whenever possible, try to leave
objects in an unaltered state in the presence of exceptions, and always leave them destructible and copyable.) Again,
since "bad_alloc" is not caught in the function, it'll flow off to the caller if thrown. If copying is successful, we can
safely destroy whatever we have and then change the "pTop" member variable. Since we've promised that
"destroyAll" won't throw anything (a promise we could make, since we've promised that our destructors won't
throw) the rest is guaranteed to work. Also, since we first get a local copy of the object assigning from, and after that
destroy our own representation, the self assignment guard ("if (this != &i)") is not necessary. It's a pure performance
boost by making sure we do nothing at all instead of duplicating the representation, just to destroy the original.
With the aid of the "destroyAll" helper function, the destructor becomes trivial:
intstack::~intstack(void)
{
destroyAll();
}
So, how is this magic "destroyAll" helper function implemented? It's actually identical with the old version of the
destructor.

void intstack::destroyAll(void) throw ()


{
while (pTop != 0)
{
stack_element* p = pTop->pNext;
delete pTop; // guaranteed not to throw.
pTop = p;
}
}
Now the only thing yet untold is how the helper function "copy" is implemented. It's the by far trickiest function of
them all.

intstack::stack_element*
intstack::copy(void) const throw (bad_alloc)
{
stack_element* pFirst = 0; // used in catch block.
try {
stack_element* p = pTop;
if (p != 0)
{ // take care of first element here.
stack_element* pPrevious = 0;

pFirst = new stack_element(p->value,0);


// Cannot throw anything except bad_alloc

if (pFirst == 0) //**1
throw bad_alloc();
pPrevious = pFirst;

// Here we take care of the remaining elements.


while ((p = p->pNext) != 0) //**2
{
pPrevious->pNext =
new stack_element(p->value,0);
// cannot throw except bad_alloc

pPrevious = pPrevious->pNext;
if (pPrevious == 0) //**1
throw bad_alloc();
}
}
return pFirst;
}
catch (...) // If anything went wrong, deallocate all
{ // and rethrow!
while (pFirst != 0)
{
stack_element* pTmp = pFirst->pNext;
delete pFirst; // guaranteed not to throw.
pFirst = pTmp;
}
throw;
}
}
To begin with, the return type is "intstack::stack_element*". The type "stack_element" is only known within
"intstack," so whenever used outside of "intstack" it must be explicitly stated that it is the "stack_element" type that
is defined in "intstack." As long as we're "in the header" of a member function, nested types must be explicitly
stated. Well within the function, it is no longer needed, since it is then known what class the type belongs to.
The whole copying is in a "try" block, so we can deallocate things if something goes wrong. The local variable
"pFirst", used to point to the first element of the copy, is defined outside of the "try" block, so it can be used inside
the "catch" block. If we didn't leave this for the "catch" block, there would be no way it could find the memory to
deallocate.
If "pTop" is non-zero, the whole structure that "pTop" refers to is copied.
There are two details worth mentioning here.
• The "if" statements marked //**1 are only needed for older compilers. New compilers automatically throw
"bad_alloc" when they're out of memory. Old compilers, however, return 0.
• The "while" statement marked //**2 might look odd. What happens is that the variable "p" is given the
value of "p->pNext", and that value is compared against zero. Remember that assignment is an expression,
and that expression can be used, for example, for comparisons. The assignment "p=p->pNext" must be in a
parenthesis for this to work. The precedence rules are such that assignment has lower precedence than
comparison, so if we left out the parenthesis, the effect would be to assign "p" the value of "p->pNext"
compared to 0, which would not be what we intended.
At the places where a "stack_element" is allocated, it is important that the "pNext" member variable is given the
value 0, since it is always put at the end of the stack. If it was not set to 0, it would not be possible to know that it
was the last element, and our program would behave erratically. It's not until we have successfully created another
element to append to the stack, that the "pNext" member variable is given a value other than 0.
Now, it's up to you to toy with the "intstack". Whenever you have a need for a stack of integers, here you have one.

Exercises
• When is guarding against self assignment necessary? When is it desirable?
• How can you disallow assignment for instances of a class?
• The non-const version of "top" returns a reference to data internal to the class. Mail me your reasons for
why this can be a bad idea (it can, and usually even is!) Can it be bad in this case?
• When can returning references be dangerous? When is it not?
• Mail me an exhaustive list of reasons when assignment or construction can be allowed to fail under the
Orthodox Canonical Form.
• When is it OK to use the auto-generated copy constructor and copy assignment operator?

Recap
This month, yet more news has been introduced to you, as coming C++ programmers.
• You have seen how C++ references work.
• You have learned about "const", and how it works for objects.
• You have seen how you can make member functions callable for "const" objects by declaring them as
"const", and seen that member functions declared "const" are callable for non-const objects as well.
• You have found out how you can overload member functions on "constness" to get different behaviour for
const objects and non-const objects.
• You have learned about the "Orthodox Canonical Form", which always gives you construction from
nothing, construction by copying, assignment and destruction.
• You have learned that your objects should always be in a destructible and copyable state, no matter what
happens.
• You have seen how you can implement common behaviour in private member functions. These member
functions are then only callable from within member functions of that class.

Coming up
Next month I hope to introduce you to components of the C++ standard library. Most compilers available today do
not have this library, but fortunately it is available and downloadable for free from a number of sources. Knowing
this library, and how to use it, will be very beneficial for you, partly because it is standard, and partly because it's
remarkably powerful.
As usual, you are the ones who can make this course the ultimate C++ course for you. Send me e-mail at once,
stating your opinions, desires, questions and (of course) answers to this month's exercises!

Capitulo 4
NOTE: Here is a link to a zip of the source code for this article. Ed.]
So I've done it again, promised something I cannot keep. I wanted to introduce you to the C++ standard library, but
there are problems with the available implementations and Watcom compilers, and I don't own a Watcom compiler
to work around it with... Later. This month, however, we'll look at another very important aspect of C++, that of
templates. A template is a way of loosening your dependency on a type, without sacrificing type safety (this will get
clear later). Templates are the foundation of the standard C++ library too, so getting to know them before hand
might not be so bad anyway.

Why templates
The last two articles made some effort in perfecting a stack of integers. Today, I want a stack of doubles. What do I
do? Rewrite it all and call it doublestack? It's one alternative. Then I want a stack of char* (another rewrite) and a
stack of bicycles (yet a rewrite, and a bizarre view). And then, of course, we end up with 4 versions of stack, all with
identical code, just one data member in the internal struct with different type for all of them. Sigh...
There's of course the C kind of solution, always make it a stack of void*, and cast to whatever you want (and just
hope you won't cast to the wrong type). No, the latter alternative isn't an alternative in my book. Type safety is
essential for writing solid programs (Smalltalk programmers disagree). The former alternative isn't an alternative
either. Just think of this little nightmare, 4, at least, more or less identical pieces of code. When you find a bug
(when, not if), you have to correct it in as many places. Yuck... OK, so I guess I've explained what templates are for.
They're the solution to the above problem. But how?

Function templates
In the first C++ article, I wrote a set of overloaded functions called "print", which printed parameters of different
types. The code in each of those functions was exactly the same (exactly the kind of redundancy that's always to be
avoided). This is an ideal place for a template. Here's what a template function for printing something can look like:

template <class T>


void print(const T& t)
{
cout << "t=" << t << endl;
}
The keyword "template" says we're dealing with a template. When declaring/defining a template, there's always a
template parameter list, enclosed in a '<', '>' pair. The template parameter for this template is "class T". This means
that the template deals with a type, some type, called T. Despite the keyword "class", T does not have to be a class,
it can be any of the built in types, enumerations, structs, and so on (if you have a modern compiler, it will accept the
keyword "typename" instead of "class", although "class" will still work). The name "T" is of course arbitrarily
chosen. It could be any name.
After this comes the function definition, where T is used just as if it was a legal type.
For writing a template function, that's really all there is. Here are some examples using it:

int main(void)
{
print(5); // print<int>
print(3.141592); // print<double>
print("cool"); // print<const char*>
print(2); // print<int> again.
return 0;
}
Weird? OK, time for some demystifying. The code for the template, is not a function. It's a function template,
something which the compiler uses to create functions. This is very much like a cookie cutter. Once you have a
cookie cutter, you can make cookies with the shape of the cutter. More or less any kind of cookie can be made with
that cutter. When the compiler reads the function template, it does pretty much nothing at all, other than to
remember that there's a function template with one template parameter and the name "print". When the compiler
reaches "main", and sees the call to "print(5)", it looks for a function "print" taking an "int" as a parameter. There is
none, so it expands the template function "print" with the type "int", and actually makes a new function. Note that
this is done by the compiler at compile time. The same happens for the other types. The compiler always first checks
if there is a function available, and if there isn't, it tries to create it by expanding the function template. This order of
things is necessary to avoid unnecessary duplication. After all, "print(2)" uses the same function as "print(5)" does,
rather than creating yet another copy of it.
Let's compile and run:
[c:\desktop]icc /Q temp_test.cpp

[c:\desktop]temp_test.exe
t=5
t=3.14159
t=cool
t=2

[c:\desktop]
Although it does not seem like it, type safety is by no means compromised here. It's just seen in a somewhat
different way. For the function template "print", there's only one requirement on the type T; it must be possible to
print it with the "<<" operator to "cout". If the type cannot be printed, a compilation error occurs. To test it, here's
what GCC says when trying to print the "intstack" from last month:

[c:\desktop]gcc temp_test2.cpp -fhandle-exceptions -lstdcpp


temp_test2.cpp: In function `void print(const class intstack &)':
temp_test2.cpp:285: no match for `operator <<(class ostream, class
intstack)'
GCC delivered a compilation error, since the type "intstack" cannot be printed with "<<" on "cout" (the error
message says "ostream", which is correct. We'll deal with that later this fall/early winter, in one or a few articles on
C++ I/O).
Here the compiler generated a new function, called a template function, where every occurrence of "T" (only one, in
the function parameter list) is replaced with "intstack". After having generated the function, it compiled it, and
noticed the error. Note that a function is not generated from a function template until a call is seen (the compiler
cannot know what types to generate the function for before that).
Please note the different meanings of the terms "function template", and "template function". The "function
template" is what you write. It's a template from which the compiler generates functions. The compiler generated
functions are the template functions. The "function template" is the cookie cutter, while the "template function" is
the cookie. One example of a template function above, is "print<int>()" (i.e. the "int" version of print).

Templates and exceptions


As you may have noticed, I didn't write an exception specifier for the "print" function template. This was not a
mistake, nor was it sloppiness. The drawback with templates is that they make writing exception specifiers a bit
difficult. I could try to make the promise that the function "print" does not throw exceptions, by adding the
exception specifier "throw ()", but that would not be wise. The problem is that I cannot know what kind of type T
will be, and I cannot know if operator<< on that type can throw an exception or not. What if it does? If so, and the
function template had an empty exception specifier list, "unexpected" would be called, and the program terminate.
Not nice. This problem is something I strongly dislike about C++, but this is how it works, and there's not much to
do about it. I wish there was a way to say "The exceptions that might be thrown are the ones from operator<< on T"
but there is no way to say that, other than as a comment. Note that not writing an exception specifier means that any
exception may be thrown.

Class templates
Just as you can write functions that are independent of type (and yet type safe!) we can write classes that are
independent of type. In a sense, class templates exist as builtins in C and C++. You have arrays and pointers (and
references) that all act on a type, some type. The type they act on does not change their behaviour, they're still
arrays, pointers and references, but of different types. Let's explore writing a simple class template, by improving
the old "Range" class from lesson 2. In case you don't remember, the original "Range" looks like this:

struct BoundsError {};


class Range
{
public:
Range(int upper_bound = 0, int lower_bound = 0)
throw (BoundsError);
// Precondition: upper_bound >= lower_bound
// Postconditions:
// lower == upper_bound
// upper == upper_bound
int lowerBound() throw ();
int upperBound() throw ();
int includes(int aValue) throw ();
private:
int lower;
int upper;
};
This class is a range of int. There's no reason, however, why it shouldn't be a range of any type. Writing a class
template is in many ways similar to writing a function template:

struct BoundsError {};

template <class T>


class Range
{
public:
Range(const T& upper_bound = 0,
const T& lower_bound = 0);
// Precondition: upper_bound >= lower_bound
// Postconditions:
// lower == upper_bound
// upper == upper_bound
// Throws:
// Bounds error on precondition violation
// Whatever T's copy constructor throws.
// Whatever operator < on T throws.

const T& lowerBound() throw ();


const T& upperBound() throw ();
int includes(const T& aValue);
// Throws: Whatever operator>= and operator <= on T
// throws.
private:
T lower;
T upper;
};
As can be seen, after "template <class T>", on line 3, T is used just as if it was a type existing in the language. I've
changed the constructor so that it accepts the parameters as const reference instead of by value. The reason is
performance if T is a large type (if passed by value, the parameters must be copied and the copying may be an
expensive operation). I've also removed the exception specifier, and instead used a comment, since after all, there is
no way to know if T throws anything.
"lowerBound", "upperBound" and "includes" uses const T& instead of value, for the same reason as the constructor
does. "lowerBound" and "upperBound" can safely have empty exception specifiers, since those member functions
do not do anything with the T's. They just return a reference to one of them. "includes" on the other hand, does need
the unfortunate comment.
Time for the implementation, which will include some news:

template <class T>


Range<T>::Range(const T& upper_bound,
const T& lower_bound)
: lower(lower_bound), // copy constructor
upper(upper_bound) // copy constructor
{
if (upper < lower) throw BoundsError();
}

template <class T>


const T& Range<T>::lowerBound() throw ()
{
return lower;
}
template <class T>
const T& Range<T>::upperBound() throw ()
{
return upper;
}

template <class T>


int Range<T>::includes(const T& aValue)
{
return aValue >= lower && aValue <= upper;
}
The syntax for member functions is very much the same as that for function templates. The only difference is that
we must refer to the class (of course), and we must specify that it's the template version of the class, by adding
"<T>" after the class name. The reason is that we're not dealing with a complete class, but with a class template, and
we must be explicit about that. We must also precede every member function with "template <class T>".
There isn't much more to say about this. Let's have a look at how it's used:

#include <iostream.h>

int main(void)
{
Range<int> ri(100,10);
Range<double> rd(3.141592,-3.141592);
if (ri.includes(55))
{
cout << "[" << ri.lowerBound() << ", "
<< ri.upperBound() << "] includes 55"
<< endl;
}
if (!rd.includes(62))
{
cout << "[" << rd.lowerBound() << ", "
<< rd.upperBound()
<< "] does not include 62" << endl;
}
return 0;
}
Take a careful look at the syntax here. To use a class template, you must explicitly state what type it is for. There is
unfortunately no way to say "Range(5,10)" and have the compiler automatically understand that you mean
"Range<int>(5,10)". As with function templates, a class template is expanded when it's referred to, so when the
compiler first sees "Range<int>", it creates the class, by expanding whatever is needed. The compiler will also treat
every member function just as any template function, i.e. the code will not be expanded until it is called from
somewhere. The above code calls all members of "Range", but had "includes" not been called, it would not have
been expanded. One unfortunate side of this is that "includes" could actually contain errors, and this would be
unnoticed by the compiler, until "includes" was called.

Advanced Templates
Now that the basics are covered, we should have a look at some power usage (this section is abstract, so it may
require a number of readings).
One unusually clever place for templates, is as something called "traits classes". A traits class is never instantiated,
and doesn't contain any data. It just tells things about other classes, that is its sole purpose. The name "traits class" is
odd. Originally they were called "baggage classes", since they're useless on their own, and belong to something else,
but for some reason some people didn't like the name, so it was changed. My intention is to write a traits class,
which tells the name of the type it is specialized for (explanation of that comes below), and to write a special
template print, which prints ranges looking like the constructor call for the range, and finally, a function template,
which is used to create ranges, without needing to specify the type. When done, I will be able to write:

print(make_range(10,4));
and when executed, see:
Range<int>(10,4)
Magic? No, just templates!
Here we go...
A traits class, is a simple class template. The traits class needed here, is one that tells the name of a type. The class
template just looks like this:

template <class T>


class type_name
{
public:
static const char* as_string();
};
That is, it holds no data, and the member function is declared as "static". This is the way traits classes usually look.
No data, and only static member functions. A member function declared static, is different from normal member
functions, in that it does not belong to an instance, but belongs to the class itself. Here's an example:

class A
{
private:
int data;
public:
void f(void);
static void g(void);
static void h(void);
};

void A::f(void)
{
cout << data << endl;
}

void A::g(void)
{
cout << data << endl; // error! Cannot access data.
}

void A::h(void)
{
cout << "A::h" << endl;
}

int main(void)
{
A a;
a.f(); // prints something.
a.h(); // prints "A::h"
A::h(); // also prints "A::h"
A::f(); // Error, f is bound to an object, and must be
// called on an object.

return 0;
}
"A::g()" is in error, because it's declared static, and thus not bound to any object, and as such cannot access any
member data, since member data belongs to objects.
The calls "a.h()" and "A::h()" are synonymous. Since "h" is not tied to an object, it can be called through the class
scope operator "A::", which means it's the "h" belonging to the class named "A".
Calling "A::f()" is an error, since it is not static. This means it belongs to an object, and must be called on an object
(through the "." operator).
Now back to traits classes. The whole idea for traits classes is one of "specialization". The class template is the
general way of doing things, but if you want the class to take some special care for a certain type, you can do what's
called a specialization. A member function specialization is usually not declared, just defined, like this:
const char* type_name<char>::as_string()
{
return "char";
}
Of course, if you have a top modern compiler, you'll get a compilation error. The syntax has changed, so compilers
very much up to date with the standardization requires you to write like this:

template <>
const char* type_name<char>::as_string()
{
return "char";
}
A minor, but in a sense, understandable difference. The "template <>" part clarifies that it's a template we're dealing
with, but the template parameter list is empty, since we're specializing for known types.
This is how traits classes usually look. They have a template interface, the class, which declares a number of static
member functions. Those member functions are intended to tell something about some other class. Normally, the
template member functions are not defined, instead specializations are. Their purpose is only to tell something about
other classes, nothing else.
Now, we can use the "type_name" traits class for "char" as follows:

cout << type_name<char>::as_string() << endl;


If we try for a type we haven't specialized, such as "double", we'll get an error when compiling. You can of course
make any specializations you like. Please add all the fundamental types.
Now over to the print template, which with the above seems fairly simple. It's supposed to accept an instance of a
"Range", and print it, just as the constructor call for the "Range" was done. Piece of cake:

template <class T>


void print(const Range<T>& r)
{
cout << "Range<" << type_name<T>::as_string()
<< ">(" << r.upperBound() << ", "
<< r.lowerBound() << ")" << endl;
}
Here we see two new things; the parameter for the function template need not be the template parameter itself. It
needs to be something that makes use of the template parameter, though (for all except the absolutely newest
compilers, all template parameters must be used in the parameter list for the function). The other new thing is how
elegantly the "type_name" traits class blends with the function template. For being such an incredibly simple
construct, the traits classes are unbelievably useful. Note also that this means we cannot print ranges of types for
which the "type_name" traits class is not specialized.
Now we're almost there. We can now write:

print(Range<int>(10,5));
And it will work (if we specialize "type_name<int>::as_string()", that is).
Now for the last detail; the function template that creates "Range" instances.

template <class T>


Range<T> create_range(const T& t1, const T& t2)
{
return Range<T>(t1,t2);
}
Doesn't seem too tricky, now does it? There actually is no catch in this. The function template is by the compiler
translated to a template function, using the types of the parameters. If the types differ in a call, the compiler will give
you an error message. When the type is known, it will know what kind of "Range" to create and return. We can now
write:

print(make_range(10,5));
just as we planned to. Neat, eh? If you want to learn more about traits classes, have a look at Nathan Meyers traits
article from the June '95 issue of C++ Report.
Exercises
• Biggie: Rewrite last months "intstack" as a class template, "stack<T>" What happens if the copy
constructor, operator== or destructor of T throws exceptions?
• When can you, and when can you not use exception specifiers for templates?
• What are the requirements on the type parameter of the templatized "Range"? Can you use a range of
"intstack"?
• What are the requirements on the type parameter of the templatized "stack<T>"?

Recap
Quite a lot of news this month. You've learned:
• how to write type independent functions with templates, without sacrificing type safety.
• how the compiler generates the template functions from your function template.
• about template classes, which can contain data of a type not known at the time of writing.
• that templates restricts the usefulness of exception specifiers.
• how to specialize class templates for known types.
• how to write and use traits classes.

Coming up
If the standard library's up and running on Watcom, that'll be next month's topic, otherwise it'll be C++ I/O streams.
As always, send me e-mail at once, stating your opinions, desires, questions and (of course) answers to this month's
exercises!

Part Part Part Part Part Part Part Part Part Part1 Part1 Part1 Part1
1 2 3 4 5 6 7 8 9 0 1 2 3

Introduction
We've seen how the fundamental types of C++ can be written to the screen with "cout << value" and read from
standard input with "cin >> variable". This month, you will learn how you can do the same for your own classes and
structs. It's surprisingly easy to do.

Exploring I/O of fundamental types


Formatted I/O, is not part of the language proper in C++ (or in C for that matter.) It's handled by an I/O library,
that's implemented in the language. (If you're familiar with Pascal, try to implement something like Write and
WriteLn in Pascal. You can't, the language doesn't allow it, that's why it's built into the language itself.) We've seen
a number of times how we can print something with "cout << value". How can this be expressed in the language? To
begin with, the syntax is legal only because you can overload operators in C++. You've already seen that with
operator=. Let's see what actually happens when we use operator=.

class X
{
public:
...
X& operator=(int i);
...
};

X x;
x=5; //**
At the last line of the example, what actually happens is that operator= is called for the object named "x". Another
way of expressing this is:

x.operator=(5);
In fact, this syntax is legal, and it generates identical code, because this is how the compiler will treat the more
human-readable form "x=5".
As we can see then, an operator overridden in a class, is just like any other member function, it's just called in a
peculiar form.
Let's go back to printing again. "cout" is an object of some class, which has operator<<(T) overloaded, where T is
any of the fundamental types of C++. The relevant section of the class definition looks as follows:

class ostream
{
...
public:
...
ostream& operator<<(char);
ostream& operator<<(signed char);
ostream& operator<<(unsigned char);
ostream& operator<<(short);
ostream& operator<<(unsigned short);
ostream& operator<<(int);
ostream& operator<<(unsigned int);
ostream& operator<<(long);
ostream& operator<<(unsigned long);
ostream& operator<<(float);
ostream& operator<<(double);
ostream& operator<<(long double);
ostream& operator<<(const char*);
...
};
The value returned by each of these is the stream object itself (i.e. if you call "operator<<(char)" on "cout", the
return value will be a reference to "cout" itself.)
With the above in mind, we can see that writing

int i;
double d;

cout << i << d;


is synonymous with

int i;
double d;
(cout.operator<<(i)).operator<<(d);
The only difference for reading is that the class is called "istream" instead, and that the operator used is
operator>>().

I/O with our own types


The most important thing to recognise is that our own types (classes and structs) always consists of fundamental
types. This is important. The C++ I/O library only supports I/O of the fundamental types, so if our own data types
consisted of something completely different, I/O would be very difficult indeed.
So, how do we make sure we can do I/O on ranges and stacks (from the earlier lessons?) What about extending our
own class with the members operator<< and operator>>? This would, sort of, work, but the syntax would change.
As I wrote above, "a << b" is identical with "a.operator<<(b)", and if we add operators << and >> to our class, we'll
require our object on the left hand side, and the stream to print on/read from, on the right hand side, and that's not
what we want. Another possible way of doing this is to edit the ostream and istream class to contain operator<< and
operator>> for our own classes. Does that seem like a good idea to you? It doesn't to me.
The solution does yet again lie in operator overloading, but this time in a somewhat different way. We just saw how
we can overload an operator for a class, such that the operator becomes a member function for that class (only, in its
use, the syntax differs.) It's also possible to overload operators, such that the operator becomes a function, provided
that at least one of the parameters to the operator is not a built-in type. Most operators that can be defined like a
nonmember function, accept two parameters. Such is the case for our new friends operator<< and operator>>.
Let's revisit our old friend, the class "Range." This is the definition of "Range", for those who do not have old issues
handy (I've added "const" on the member functions, now that you know what it's for. See part 3 for details if you've
forgotten):

struct BoundsError {};


class Range
{
public:
Range(int upper_bound = 0, int lower_bound = 0)
throw (BoundsError);
// Precondition: upper_bound >= lower_bound
// Postconditions:
// lower == upper_bound
// upper == upper_bound

int lowerBound() const throw ();


int upperBound() const throw ();
int includes(int aValue) const throw ();
private:
int lower;
int upper;
};
How should this thing be printed and read? Here's a wishlist. We'll reduce it a little bit, to be more realistic later.
1. The syntax and semantics for printing must be the same as for the fundamental types of C++.
2. Full commit or roll back, that is, either we print all there is to be printed, or we print nothing at all.
3. The print must be in a form distinguishable from, say, two integers separated by a comma.
4. Full type safety
5. Encapsulation not violated.
6. No unnecessary computations.
7. We want printing and reading synchronized (i.e., if we read something, then print a range, then reads
something, we want the reading to complete before printing, and we want it all printed before reading
again.) Since both reading and writing is normally buffered, it is not at all obvious that this will occur.
All of these are possible, but #2, #6 and #7 are usually skipped. I'll skip #2 for now.
What's the appearance we want of a range when printed, and what format should we accept when reading? A golden
rule in I/O (and not just in C++) is to be very strict in your output, but very liberal in what you accept as input.
Normally, the C++ I/O library handles just exactly this for you. For format I chose is "[upper,lower]", no spaces
anywhere. On input however, white space is allowed before the first bracket, and between any of the tokens (the
tokens here are '[', number, ',' and ']').
OK, so now we have a pretty good picture on what to do, now... how? Overloading operator<< as a global function.
The signature becomes:

ostream& operator<<(ostream&, const Range&);


This declares a function, which has the syntax of a left shift operator. If we have code like:

Range r;
int i;
...
cout << r << i;
The compiler will treat it as

operator<<(cout, r).operator<<(i);
This even works for more complex expressions, like:

Range r;
int i;
int j;
...
cout << i << r << j;
Which the compiler interprets as:
operator<<(cout.operator<<(i),r).operator<<(j);
Study these examples carefully, to make sure you understand what's going on.
Now, after these examples, it's fairly easy to get down to work with implementing the operator<< function.

ostream&A& operator<<(ostream& os, const Range& r)


{
os << '[' << r.upperBound()
<< ',' << r.lowerBound() << ']';
return os;
}
Here "r" is passed as const reference, since the function does not alter "r" in any way (and promises it won't.) The
stream, "os", however, is passed by non-const reference. This is essential. Printing does alter a stream. It will not be
the same after printing as it was before printing. It is not possible to pass it by value, since when passing by value,
means copying, and copying a stream doesn't make much sense (think about it.) Inside the function, we're printing
known types, char and int, so the operator<< provided by the I/O class library suits just fine.
How well does this suit the 7 points above? The syntax is correct, and the semantics are too, given the facts known
this far (more is needed, as you will see further down.) We do not have full commit or rollback, but I mentioned
already in the beginning that we'll skip that for now. The format is distinct enough, we have type safety and
encapsulation is not violated. This is as far as most books on C++ cover when it comes to printing your own types.
However, we do make some unnecessary computations if the stream is bad in one way or the other. Say, for
example, we have a detached process. Detached processes do not have standard output and standard input (unless
redirected) and as such printing will always fail. Why then, even try? We also do not synchronize our output with
input. The check and synchronization is simple to make, but oddly enough not mentioned in most C+ books.

ostream& operator<<(ostream& os, const Range& r)


{
if (!os.opfx())
return os;
os << '[' << r.upperBound()
<< ',' << r.lowerBound() << ']';
os.osfx();
return os;
}
The "prefix" ("opfx" means "output prefix") function checks for a valid stream, and also synchronizes output with
input. The "suffix" ("osfx" means "output suffix") signals end of output, so that synchronized input streams can
begin accepting input again.) I dare you to find this in a C++ book (I know of one book.) I don't know why it's just
about always skipped, since it isn't more difficult than this to avoid unnecessary computations and synchronize input
with output.
That was printing, how about reading? The signature and general appearance of the function is pretty much clear
from the above discussions. Let's make a try:

istream& operator>>(istream& is, Range& r)


{
if (!is.ipfx())
return is;
char c;
is >> c;
if (c != '[')
// signal error somehow and roll back stream.
;
int upper;
is >> upper;
is >> c;
if (c != ',')
// signal error somehow and roll back stream.
;
int lower;
is >> lower;
is >> c;
if (c != ']')
// signal error and roll back stream.
;
r=Range(upper,lower);
is.isfx(); // ERROR! Does not exist!
return is;
}
Hmm... OK, so reading wasn't as easy... There are three issues above that needs to be resolved. How to signal error,
how to roll back the stream, and how to deal with the suffix function, since the guess "is.isfx()" was wrong. Let's
begin from the easy end, the suffix function. The solution is that there isn't one, so we needn't even try. The problem
is fixed by removing the faulty line (don't you just love bugs that you fix solely by removing code!)
Rolling back the stream is interesting indeed, since it's very difficult to do. In fact, it's almost impossible. We can put
back a character. One character, that is all that is guaranteed to work. In other words, our only chance is if the first
character read is not right. Putting back a character is done with "istream::putback(char)". It's also absolutely
necessary that the character put back is the same as the last one read, otherwise the behaviour is undefined (which
literally means all bets are off, the program may do *anything*, but in practice it means you cannot know if it just
backs a position, or actually changes the character.)
The obvious solution to signalling an error, to throw an exception, is wrong. The reason is conceptual. Use
exceptions to signal exceptional situations, and other means to handle the expected. The wrong input *is* expected.
Remember you're dealing with input generated by human beings here. Sure you can, in theory, demand that the
users of your program enter the exact right data in the exact correct format every time, but you won't be very popular
among them, and soon will have none. No, erroneous user input is expected, and thus not exceptional, and thus not
to be handled with exceptions. How then?
A stream object has an error state consisting of three orthogonal failure flags. "bad", "eof" and "fail". "eof" is used to
signal end of file, a not too unusual situation (as a matter of fact, a situation most programs rely on, but if it occurs
in the middle of reading something, it's usually a failure.) "fail" is the one we're interested in here, it's used to signal
that we received something that was not what we expected, but the stream itself is OK. "bad" is something we hope
to never see, since it means the stream is really out of touch with reality and we cannot trust anything from it (I've
only seen this one once, and it was due to a bug in a library!) I guess we can expect "bad" if reading from a file, and
hit a bad sector.
So, what we should do if we read something unexpected, is to set the stream state to "fail." This is done with the odd
named member function "clear(int)". "clear" sets the status bits of the stream to the pattern of the integer parameter
(which defaults to 0, so if nothing is passed, the name makes sense.) The bits we can set are "ios::badbit",
"ios::failbit" and "ios::eofbit". We can get the current status bits by calling "is.rdstate()", and usually we want to do
that when setting or resetting a status bit, since we want to affect only that bit, and leave the other bits as they were
before the call. The status bits can also be checked with the calls "is.fail()", "is.bad()" and "is.eof()" (which return 0
if the bit they represent is not set, and non-zero otherwise.) A fourth call "is.good()" returns non-zero if no error state
bits are set, and 0 otherwise. Now with the above in mind, let's make another try:

istream& operator>>(istream& is, Range& r)


{
if (!is.ipfx())
return is;
char c;
is >> c;
if (c != '[')
{
is.putback(c);
is.clear(ios::failbit|is.rdstate());
return is;
}
int upper;
is >> upper >> c;
if (c != ',')
{
is.clear(ios::failbit|is.rdstate());
return is;
}
int lower;
is >> lower >> c;
if (c != ']')
{
is.clear(ios::failbit|is.rdstate());
return is;
}
if (is.good()) {
if (upper >= lower)
r=Range(upper,lower);
else
is.clear(ios::failbit|is.rdstate());
}
return is;
}
This actually solves the problem as far as is possible. The call to "is.ipfx()" not only synchronizes the input stream
with output streams, but also checks for error conditions and reads past leading white space. If the first character
read is not a '[', we put the character back and set the fail bit (the order is important, "putback" is not guaranteed to
work if the stream is in error.) After this we read the upper limit of the range, and the separator. Note that
operator>> for built in types skips leading whitespace, so we needn't work on that at all. If the separator is not ",",
mark the stream as failed, and return. Then read the lower limit and the terminator. If the terminator is not ']', we set
the stream state to failed and return. If reading of either upper limit or lower limit failed, the stream is set to fail
state, and other reads will not do anything at all (not even alter the stream error state,) thus the check near the end for
"is.good()" is enough to know if all parts were read as we expected. If they were, all we need to do is to check that
the upper limit indeed is at or above the lower limit (precondition for the range) and if so set "r" (since we haven't
declared an assignment operator, the compiler did it for us, so the call is valid,) otherwise set the fail error state.
How well do we match the 7 item wish list? You check and judge; I think we're doing fine, and in fact better than
what can be found in most books on the subject.

Formatting
There are a number of ways in which the output format of the fundamental types of C++ can be altered, and a few
ways in which the requirements on the input format can be altered. For example, a field width can be set, and
alignment within that field. For integral types, the base can be set (decimal, octal, hexadecimal). For floating point
types the format can be fixed point or scientific. All of these, and yet some, are controlled with a few formatting
flags, and a little data. All flags are set or cleared with the member functions "os.setf()" and "os.unsetf()". I think
they're difficult to use, but fortunately there are easier ways of achieving the same effect, and we'll visit those later.
The base for integral output is altered with a call to "os.setf(v, ios::basefield)", where v is one of "ios::hex",
"ios::dec" or "ios::oct". As a small example, consider:

#include <iostream.h>

int main(void)
{
int i=19;
cout << i << endl;
cout.setf(ios::hex, ios::basefield);
cout << i << endl;
cout.setf(ios::oct, ios::basefield);
cout << i << endl;
cout.setf(ios::dec, ios::basefield);
cout << i << endl;
return 0;
}
The result of running this program is:

19
13
23
19
The base is converted as expected, but there is no way to see what base it is. This can be improved with the
formatting flag ios::showbase, so let's set that one too.

int main(void)
{
int i=19;
cout.setf(ios::showbase);
cout << i << endl;
cout.setf(ios::hex, ios::basefield);
cout << i << endl;
cout.setf(ios::oct, ios::basefield);
cout << i << endl;
cout.setf(ios::dec, ios::basefield);
cout << i << endl;
return 0;
}
The output of this program is

19
0x13
023
19
That's more like it, right? The call to "setf()" for setting the "ios::showbase" flag is different, though. "setf()" is
overloaded in two forms. One accepts a set of flags and a mask, the other one a full set of flags only. All the
formatting flags of the iostreams are represented as bits in an integer, and the version with the mask clears the bits
represented by the mask, except those explicitly set by the first parameters. Formatting bits not represented by the
mask will remain unchanged. The second form, the one accepting only one parameter, sets the flags sent as
parameter, and leaves the others unchanged (in other words, it bitwise "or"es the current bit-pattern with the one
provided as the parameter.) Now you begin to see why this is messy. If the masked version is called, and the mask is
"ios::basefield", the only formatting flags of the stream that will be affected are "ios::hex" or "ios::dec" or "ios::oct".
The three of these are mutually exclusive, so a call to "os.setf(ios::hex)", is potentially dangerous (what if "ios::oct"
was already set? Then you'd end up with both being set.) The second parameter "ios::basefield" guarantees that if
you set "ios::hex", then "ios::oct" and "ios::dec" will be cleared. While it's possible to set two, or all three of these
flags at the same time, it's not a very good idea (yields undefined behaviour.)
That was setting the base for integral types, now for something that's common to all types, field width and
alignment. The field width is set with "os.width(int)", and the curious can get the current field width by calling
"os.width(void)." Simple enough, let's try it out:

#include <iostream.h>

int main()
{
cout << '[' << -55 << ']' << endl;
cout.width(10);
cout << '[' << -55 << ']' << endl;
cout << '[';
cout.width(10);
cout << -55 << ']' << endl;
cout << '[' << -55 << ']' << endl;
return 0;
}
Executing this programs shows something interesting; the width set does not affect the printing separate characters,
and the width is reset after printing the first thing that uses it. This is not very intuitive I think. The result of running
the program is shown below:

[-55]
[ -55]
[ -55]
[-55]
Had you expected this? I didn't, for sure.
Now, let's play with alignment within a field. If the field width is not set, or the field width set is smaller than that
necessary to represent the value to be printed, alignment doesn't matter, but if there's extra room, alignment does
make a difference. Alignment is set with the two parameter version of "os.setf()", where the first parameter is one os
"ios::left", "ios::right", or "ios::internal", and the second parameter is "ios::adjustfield". As with the base for integral
types, the three alignment forms are mutually exclusive, so don't set two of them at the same time. Let's alter the
width setting program to show the behaviour.

#include <iostream.h>

int main()
{
cout.setf(ios::right, ios::adjustfield);
cout << '[' << -55 << ']' << endl;
cout.setf(ios::left, ios::adjustfield);
cout << '[' << -55 << ']' << endl;
cout.setf(ios::internal, ios::adjustfield);
cout << '[' << -55 << ']' << endl;
cout.width(10);
cout.setf(ios::right, ios::adjustfield);
cout << '[' << -55 << ']' << endl;
cout.width(10);
cout.setf(ios::left, ios::adjustfield);
cout << '[' << -55 << ']' << endl;
cout.width(10);
cout.setf(ios::internal, ios::adjustfield);
cout << '[' << -55 << ']' << endl;
return 0;
}
The result of running this is, after the above explanations, not very surprising:

[-55]
[-55]
[-55]
[ -55]
[-55 ]
[- 55]
Well, OK, I found the formatting of "ios::internal" to be a bit odd, but it kind of makes sense.
If the field width is larger than that required for a value, the current alignment defines where in the field the value
will be, and where in the field space will be. Space, but the way, is just the default, we can change the "padding
character", by calling "os.fill(char)", and get the current value with a call to "os.fill(void)". Let's exercise that one
too:

#include <iostream.h>

int main()
{
cout.width(10);
cout.fill('.');
cout << -5 << endl;
cout.width(10);
cout << -5 << endl;
return 0;
}
Running it yields the surprising result

........-5
........-5
Why was this surprising? Earlier we saw that the field width is "forgotten" once used. The pad character, however,
remains the same until explicitly changed.
Now that you have the general idea, why not try the other formatting flags there are:
• ios::fixed and ios::scientific control the format of floating point numbers (the mask used is ios::floatfield.)
ios::showpos controls whether a "+" should be prepended to positive numbers or not (just like a "-" is
prepended to negative numbers.
• ios::uppercase controls whether hexadecimal digits should be displayed with upper case letters or lower
case letters.
• ios::showpoint controls whether the decimals should be shown for floating point numbers if they are all
zero.
The only thing remaining for formatting is "os.precision", which comes in two flavours. One without parameters
which reports the current precision, and one with an int parameter. The unpleasant thing about this parameter, is that
many compilers interpret it differently. Some think the precision is the number of digits after the decimal point,
while most think it's the number of digits to display. The November 1997 draft C++ standards document (which, by
the way, most probably is the final C++ standards document,) says the number of digits after the decimal point is
what's controlled, but I'm not sure if that's what the current standards document says.
At any rate, inconsistencies aside, this is a mess, isn't it?

An easier way
The authors of the I/O package realized that this is a mess, so they defined something called "manipulators." You've
already used one manipulator a lot, "endl." A manipulator does may, or may not, print something on the stream, but
it will alter the stream in some way. For example "endl" prints a new line character, and flushes the stream buffer.
There are two kinds of manipulators, those accepting a parameter, and those that does not. Let's first focus on those
that don't, just like "endl." The ones available are: "dec", "hex", "oct", "endl", "ends", and "flush". Their use is
simple:

#include <iostream.h>

int main(void)
{
cout << hex << 127 << " " << oct << 127 << " "
<< oct << 127 << endl;
return 0;
}
The advantage of this is both that the code becomes clearer, and that there's no way you can accidentally set illegal
base flag combinations. "ends" is rarely used, it's there to print a terminating '\0' (the terminating '\0' of strings is
never printed normally.) "flush" flushes the stream buffer (i.e. forces printing right away.)
How do these manipulators work? There's a rather odd looking operator<< for output streams. It looks like:

ostream& operator<<(ostream& (*f)(ostream&))


{
return f(*this);
}
Now, what on earth does this mean? It means that if you have a function accepting an ostream& parameter, and
returning an ostream&, that function can be "printed," and if you do, the function will be called with the stream as
its parameter. Let's exercise this by rolling our own "left" alignment manipulator:

ostream& left(ostream& os)


{
os.setf(ios::left, ios::adjustfield);
return os;
}
This function matches the required signature, so if we "print" it with "cout lt;< left", the above mentioned
operator<< is called, and it in its turn calls the function for the stream, so "cout << left", actually ends up as
"left(cout)". Cool, eh? Roll your own "right" and "internal" manipulators as a simple exercise (they're handy too.)
Then there are some manipulators accepting a parameter. To access them, you need to #include <iomanip.h>. The
ones usually accessed from there are "setw" (for setting the field width,) "setprecision", and "setfill". Their use is
fairly straightforward and doesn't require any example.
Every compiler I've seen provides its own mechanism for writing such manipulators, so doing it in a portable way is
very difficult. Or actually, it isn't if you skip the mechanism offered by your compiler vendor and do the job
yourself, because it really is simple. Let's write one that prints a defined number of spaces:

class spaces
{
public:
spaces(int s) : nr(s) {};
ostream& printOn(ostream& os) const {
for (int i=0; i < nr; ++i)
cout << ' ';
return os;
}
private:
int nr;
};
ostream& operator<<(ostream& os, const spaces& s)
{
return s.printOn(os);
}
Can you see what happens if we call "cout << spaces(40)"? First the object of class "spaces" is created, with a
parameter of 40. That parameter is in the constructor stored in the member variable "nr". Then the global operator<<
for an ostream& and a const space& is called, and that function in its turn calls the printOn member function for the
spaces object, which goes through the loop printing space characters.
I think writing manipulators requiring parameters this way is lots easier than trying to understand the non-portable
way provided by your compiler vendor.
Now something for you to think about until next month, what about our I/O of our own classes with respect to the
formatting state of the stream? How's the "Range" class printed if the field width and alignment is set to something?
How should it be printed (hint, your probably want it printed differently from what will be the case if you don't take
care of it.)

Exercises
• Find out which formatting parameters "stick" (like the choice of padding character) and which ones are
dropped immediately after first use (like the field width.)
• With the above in mind, and remembering that destructors can be put to good work, write a class which will
accept an ostream as its constructor parameter, and which on destruction will restore the ostreams
formatting state to what it was on construction.
• Experiment with the formatting flags on input, which have effect, and which don't? Of those that do have
an effect, do they have the effect you expect?
• Write an input manipulator accepting a character, which when called compares it with a character read from
the stream, and sets the ios::fail status bit if they differ.

Recap
This month you've learned a number of things regarding the fundamentals of C++ I/O. For example
• How to set, clear and recognise the error state of a stream.
• Why exceptions are not to be used when input is wrong.
• How to make sure your own classes can be written and read.
• The very messy, and the somewhat less messy way of altering the formatting state of a stream.
• How to write your own stream manipulators.

Standards update
• The prefix and postfix functions are history. Instead you create an object of type istream::sentry or
ostream::sentry, and check it, like this:

istream& work(istream& is)


{
istream::sentry cerberos(is);
if (kerberos) {
...
}
return is;
}

The destructor of the sentry object does the work corresponding to that of the postfix function.
• "istream" and "ostream" are in fact not classes in the standard, but typedef's for class templates. The class
templates are template <class charT, class traits> class basic_istream<charT, traits>, and template<class
charT, class traits> class basic_ostream<charT, traits>. "istream" is typedefed as "basic_istream<char,
char_traits<char> >", and "ostream" as "basic_ostream<char, char_traits<char> >". There's also the pair
"wistream" and "wostream", that are streams of wide characters.
• The mechanism for writing manipulators is standardised (and heavily based on templates.) I still think it's
easier to write a class the way I showed you.
• Any operation that sets an error status bit may throw an exception. Which error status bits cause exceptions
to be thrown is controlled with an exception mask (a bit mask.) By default, though, no exceptions are
thrown.
• Formatting of numeric types (and time) is localised. By default most implementations will probably use the
same formatting as they do today, but with the support for "imbuing" streams with other locales (formatting
rules.)
• The header name is <iostream> (no .h) and the names actually std::istream and std::ostream (everything in
the C++ standard library is named std::whatever, and every standard header is named without trailing .h)

Coming up
Next month we'll have a look at inheritance. Inheritance is what Object Orientation is all about. People who
enjoy and understand the philosophy of Platon will feel at home. Inheritance is a way of expressing
commonality.
As always, send me e-mail at once, stating your opinions, desires, questions and (of course) answers to this
month's exercises!

Part1 Part2 Part3 Part4 Part5 Part6 Part7 Part8 Part9 Part10 Part11 Part12 Part13

Int
Part Part Part Part Part Part Part Part Part Part1 Part1 Part1 Part1
1 2 3 4 5 6 7 8 9 0 1 2 3

Introduction
I admit it. I've had very little inspiration for writing this month. Maybe it's the winter darkness, or the to be switch of
jobs. However, instead of leaving you in the dark for a month, here's some food for thought, even though it's short
and not the planned details on inheritance.
Example:
Study this function template:

template <class IN, class OUT>


OUT copy(IN begin, IN end, OUT dest)
{
while (begin != end) {
*dest = *begin;
++begin;
++dest;
}
return dest;
}
What does it mean? Let us first have a look at the requirements on the types for IN and OUT.
IN: Must be copy-able (since the parameters are passed by value, not by reference.) Must be comparable with
operator !=. Must have an operator*, whose return value must be assignable. Operator ++ (prefix) must be allowed.
OUT: Must be copy-able, both for the parameter and the return value. Must have operator*, whose return value must
be something which can be assigned to the result of operator* for IN. Operator++ (prefix) must be allowed.
One match for "IN" and "OUT" is obvious: a pointer in an array. Let's say that the types are "T1*" and "T2*", then
this is legal for all types "T1" that can be assigned (or implicitly converted to, from) a type "T2".
For example:

int iarr[]={ 12,23,34,45};


size_t isize=sizeof(iarr)/sizeof(iarr[0]);
double darr[isize];
copy(iarr,iarr+isize,darr);
So, what does the above do? The name no doubt gives a hint, but let's analyze it. At the call-site, the function
template is expanded to a template function, as follows:
double copy<int*,double*>(int* begin, int* end, double* dest)
{
while (begin != end) {
*dest = *begin;
++begin;
++dest;
}
return dest;
}
What this function does is to assign the value pointed to by "dest" the value of the dereferenced pointer "begin", as
long as "begin" does not equal "end", and then increment "begin" and "dest."
This puts a requirement on "begin" and "end" by using operator++ (prefix only) on "begin", it must be possible to
reach a state where "begin" does not compare unequal to "end." For example, "begin" might be the beginning of an
array, and "end" the end of one. Note, however, that when "begin" and "end" are equal, no copying is done. That is,
"copy(a,a,b)" does nothing at all (except return "b"). This means that to copy an entire array, like in the example
above, "end" must point one past the last element of the array, like this:

+----+-----+-----+-----+----+
primes_lt_10 = | 2 | 3 | 5 | 7 |XXXX|
+----+-----+-----+-----+----+
^ ^
| |
begin end (points to non-existing
element one past the last
one.)
Fortunate as it is, this is legal in C and C++. It illegal to dereference the "one-past-the-end" pointer, but the value is
legal, and decrementing it will make it point to the last element (as opposed to making it point n, where n>1,
elements past the end, which yields "undefined behaviour", i.e. all bets are off.)
This is useful, we can now copy arrays (or parts of arrays) of any type to arrays (or parts there of) of any type, if the
source type can be implicitly converted to the destination type, by using the copy function template. Very useful.
However, the fun has only begun. The real joy begins when we realize we can write our own types that behaves the
same way.

Other uses
Let's assume we want to print the contents of an array. How can we do this? Of course we can, as usual, use a loop
over all elements and print them, but I can assure you, we can use the copy function template to do it. How?
Printing an array (actually, the values in an array) means copying the values from the array to the screen, through
some conversion (the output formatting.) The problem thus becomes, how do we make a type that does the
necessary conversion, prints on the screen, and conforms to the requirements stated for the template parameter
"OUT?"
The secrets seems to lie in the lines "*dest = *begin" and "++dest". As I see it, there are two alternatives.
Either "*dest = *begin" prints the value of "*begin" on the screen, and "++dest" does nothing at all, or "*dest =
*begin" makes our variable "dest" remember the value to print and on "++dest" it does the printing. To show you
how this can be done, I will do the former. You can do the latter as an exercise.
Of course, it is now necessary to see how some more operators can be overloaded; operator* and operator++. Of
these, operator* is very straight- forward, while operator++ requires some thought since there are two operator++,
one postfix and one prefix (i.e. there's a difference between "dest++" and "++dest.")
Assuming a class C, operator ++ is (usually) modeled as follows (and always with these member function
signatures:)

class C
{
public:
... // misc
C& operator++(void); // prefix, i.e. ++c;
C operator++(int); // postfix, i.e. c++
... // other misc.
};
C& C::operator++(void)
{
... // whatever's needed to "increment" it.
return *this;
}

C C::operator++(int) // throw away int, it's not used, other than to


{ // distinguish between pre- and post-fix ++
C old_val(*this); // remember the old value
::operator++(); // let the prefix version do the job
return old_val; // and return the old value
}
Needless to say, decrementing is analogous.
Let's make our simple "int_writer" class, which writes integers on standard output (i.e. normally the screen.)

class int_writer
{
public:
// trust the compiler to generate necessary constructors and
destructor
int_writer& operator++();
int_writer& operator*();
int_writer& operator=(int i); // does the real writing.
};
Operator++ we implement to do nothing at all, since it's not used for anything, but operator* and operator= are
interesting. If you look at a pointer to T, dereferencing it yields a T. In this case, however, I say that dereferencing
an int_writer yields an int_writer. Weird? Well, yes. It's weird, but it makes perfect sense anyway. What do I want to
use the result of operator* for? Only for assigning to, and I want the assignment to write something on standard
output, right? If I make operator* return the very object for which operator* was called on, we can use operator= for
that class to do the writing. If we made operator* return some other type, we need to create two types, one
int_writer, and one class whose only job in life is to be assignable by int, and which very assignment actually means
writing. Perhaps the latter is purer, but the former is so much less work. Here's what the implementation looks like:

int_writer& int_writer::operator++()
{
return *this; // do nothing
}

int_writer& int_writer::operator*()
{
return *this; // do nothing
}

int_writer& int_writer::operator=(int i)
{
cout << i << endl;
return *this;
}
This means that if "dest" is of type int_writer, the line "*dest = *begin", can be expanded to:

dest.operator*().operator=(*begin);
Since the return value of "dest.operator*()" is a reference to "dest" itself, the following "operator=(*begin)" means
"dest.operator=(*begin)", and if the type of "*begin" can be implicitly converted to "int", we're writing something.
Cool eh? Here's all it takes to write the contents of the prime number array:

copy(iarr,iarr+isize,int_writer());
Of course, the name "int_writer" is a dead giveaway for a class template, isn't it? Why limit it to integers only?

template <class T>


class writer
{
public:
// trust the compiler to generate necessary constructors
// and destructor
writer<T>& operator++();
writer<T>& operator*();
writer<T>& operator=(const T&); // does the real writing.
};

template <class T>


writer<T>& writer<T>::operator++()
{
return *this;
}

template <class T>


writer<T>& writer<T>::operator*()
{
return *this;
}

template <class T>


writer<T>& writer<T>::operator=(const T& t)
{
cout << t << endl;
}
I've changed the signature for "operator=" to accept a const reference instead of a value, since T might be a type for
which copying is expensive.
The prime number copying now becomes:

copy(iarr,iarr+isize,writer<int>());
With this template, yet another requirement surfaced; for writer<T>, T must be writable through operator<<. Of
course, that's no surprise, how else would you write it?
As a last example, let's have a look at the source side, the types for "IN". Can we create a type matching the
requirements for "IN", such that a copy would read values from standard input (normally the keyboard?)
The requirements for "IN" are a little bit more complicated than those for "OUT." It must be not-equal comparable,
it must be possible to reach one value from another, through operator++, such that operator!= yields true, and
operator* must return a value.
This requires some thought, especially on the reachability issue. To make this example simple, I propose that we can
create a "reader<T>" with a number, and the number is the amount of T's to read from standard input. For every
operator++, a new T is read, and the number of reads remaining is decremented. It must also be possible to create an
"end" reader<T>, and we can use the parameter-less constructor for that. Here's how reader<T> might look like:

template <class T>


class reader
{
public:
reader(unsigned count=0);
reader<T>& operator++();
const T& operator*() const;
int operator!=(const reader<T>& r) const;
private:
unsigned remaining;
T t;
};

template <class T>


reader<T>::reader(unsigned count)
: remaining(count) // the number of remaining reads, 0 for
{ // the parameter-less constructor.
}

template <class T>


reader<T>& reader<T>::operator++()
{
if (remaining > 0 )
cin >> t; // read a new value only if
// there are values to read.
return *this;
}

template <class T>


const T& reader<T>::operator*() const
{
return t; // return the last read value.
}

template <class T>


int reader<T>::operator!=(const reader<T>& r) const
{
return r.remaining != 0 || remaining != 0;
}
The last one's perhaps debatable; I've decided that operator != is really only useful for comparing with the end, i.e. it
will only return false if both sides have reached the end (i.e. no remaining reads) state.
However, this is mighty neat:

const unsigned size=5;


float array[size];

// read 5 integers from standard input and


// store in our float array.
copy(reader<int>(size),reader<int>(),array);

// print the read values as unsigned long's


copy(array,array+size,writer<unsigned long>());

Conclusion
What you've seen here is, most probably your first ever encounter with, generic programming. The template
parameters "IN" and "OUT" (from "copy") are called "iterators," or "input iterators" and "output iterators" to be
more specific. Anything that behaves like an input iterator, can be used as one, and likewise for output iterators. We
can write input iterators for data base access, enumerating files in a directory, the series of prime numbers or
whatever you want to get values from. We can write output iterators to store values in a data base, to enter values at
the end of a linked list, to send audio data to our sound card, and whatever you need. The function template "copy"
will be useful for any combination of the above, as long as the types are convertable from *IN to *OUT. This is
*VERY* useful. If you write an algorithm in terms of generic iterators, you can use it with any kind of data
source/sink which have iterators that follows your convention.
To make matters even better, this is all part of the now final draft C++ standard. The draft contains a function
template "copy", which behaves identically to what I used in this article, and iterators called "input_iterator" and
"output_iterator" which behaves very similarly to the "reader" and "writer" class templates.
The standard documents 5 iterator categories, input iterator, output iterator, forward iterator (sort of the combination,
allows both read and write,) bidirectional iterator (like forward, but allows moving backwards too,) and lastly
random access iterators (iterators which can be incremented/decremented by more than one.) Pointers in arrays are
typical bidirectional iterators. If you write your iterators to comply with the requirements of one of these categories,
your iterators can be used with any of the algorithms that requires such iterators. Every algorithm you write can be
used with any iterators of the type your algorithm requires. That is a major time/code/debug saver.

Part Part Part Part Part Part Part Part Part Part1 Part1 Part1 Part1
1 2 3 4 5 6 7 8 9 0 1 2 3

Short recap of inheritance


Inheritance can be used to make runtime decisions about things we know conceptually, but not in detail. The
employee/engineer/manager inheritance tree was an example of that; by knowing about employees in general, we
can handle any kind of employee, including engineers, managers, secretaries, project leaders, and even kinds of
employees we haven't yet thought of, for example marketers, salesmen and janitors.

A deficiency in the model


While this is good, it's not quite enough. The classic counter example is a vector drawing program. Such a program
usually holds a collection of shapes. A shape can be a square, a circle, a rectangle, a collection of grouped images,
text, lines and so on. The problem in the model lies in the common base, shape. You know a number of things for
shapes in general; you can draw them on a canvas, you can scale them, you can rotate them and translate them. The
problem is, how do you do any of these for a shape in general? How is a generic shape drawn or rotated? It's
impossible. It's only the concrete shapes that can be drawn, rotated, translated, scaled, etc. This in itself is not a
problem, we can create our base class ``Shape'' with virtual member functions ``drawOn(Canvas&)'', ``rotate(double
degrees)'', ``translate(Coordinate c)'', ``scale(double)'' and so on, and make sure to override these in our concrete
shape classes. Herein lies the problem. How do we force the descendants to override them? One way (a bad way) is
to implement them in the base class in such a way that they bomb with an error message when called. The bad thing
with that is that it violates a very simple rule-of-thumb; ``The sooner you catch an error, the better.'' There are 5
phases in which an error can be found; design, edit, compile, link and runtime. Please note the obvious that errors
that cannot be detected until runtime might go undetected! How to discover errors at design or edit time is not for
this article (or even this article series), but there's a simple way of moving this particular discovery from runtime to
compile time.

Pure virtual (abstract base classes)


C++ offers a way of saying ``This member function must be overridden by all descendants.'' Saying so also implies
that objects of the class itself can never be instantiated, only objects of classes inheriting from it. This makes sense.
What would you do with a generic shape object? It's better to make it impossible to create one by mistake, since it's
meaningless anyway.
Here's how a pure abstract base class might be defined:

class Shape
{
public:
virtual void draw(Canvas&) = 0;
virtual void rotate(double angle) = 0;
virtual void translate(Coordinate c) = 0;
virtual void scale(double) = 0;
};
The ``= 0'' ending of a member function declaration makes it pure virtual. Pure virtual means that it must be
overridden by descendants. Having one or more pure virtual member functions in a class makes the class an abstract
base class. Abstract because you cannot instantiate objects of the class. If you try you'll get compiler errors. A class
which has only pure virtual member functions and no data is often called a pure abstract base class, or some times an
interface class. The latter is more descriptive; the class defines an interface that descendants must conform to, and
any piece of code that can understand the interface can operate on objects implementing the interface (the concrete
classes like ``Triangle'', ``Rectangle'', and ``Circle'').
The graphically experienced reader has of course noticed that rotation of a circle can be implemented extremely
efficiently by doing nothing at all, so how can we take care of that scenario? It's unnecessary to write code that does
nothing, is it not? Let's have a look at the alternatives.
• Let's just ignore it. It won't work, though, since then our ``Circle'' class will be an abstract class (at least one
pure virtual is not ``terminated.'')
• We can change the interface of ''Shape`` such that ``rotate'' is not a pure virtual, and code its
implementation to do nothing. This doesn't seem like a good idea because then the programmer
implementing the square might forget to implement ``rotate'' without getting compiler errors.
The root of this lies in the illusion that doing nothing at all is the default behaviour, while it is an optimization for
circles. As such the ``do nothing at all'' code belongs in ``Circle`` only. In other words, the best solution is with the
original pure abstract ``Shape'' class, and an empty implementation for ``Circle::rotate.''

Addressing pure virtuals


I won't write a drawing program, since that'd make this article way too long, and the point would be drowned in all
other intricacies of graphical programming. Instead I'll attack another often forgotten issue; addresses. Mailing
addresses have different formatting depending on sender and receiver country. If you send something internationally
you add the destination country to the address, while for domestic letters that's not necessary. The formatting itself
also differs from country to country. Here are a few (simplified) examples:

Sweden

Name
Street Number
{Country-Code}Postal-Code City
{Country-Name}

USA

Name
Number Street
City, State Zip
{Country-Name}

Canada and U.K.

Name
Number Street
City
{Country}
Postal-Code
Then, of course, there are totally different types of addresses. E-mail, Ham Radio call-signs, phone number, fax
number, etc.
As a simplification for this example I'll treat State and Zip in U.S. addresses as a unit, and I will assume that Postal-
Code and State/Zip in U.S. addresses are synonymous (i.e. I'll only have one field that's used either as postal code or
as state/zip combination, depending on country). As an exercise you can improve this. Make sure ``State'' is only
dealt with in address kinds where it makes sense. The Country-Code as can be seen in the Swedish address example
will also be ignored (this too makes for an excellent exercise to include). The address class hierarchy will be done
such that other kinds of addresses like e-mail addresses and phone numbers can be added.
Here's the base class:

class Address
{
public:
virtual const char* type() const = 0;
virtual void print(int international=0) const = 0;
virtual void acquire(void) = 0;
virtual ~Address();
};
The idea here is that ``type'' can be used to ask an address object what kind of address it is, a mailing address, e-mail
address and so on. If the parameter for ``print'' is non-zero, the address will be printed in international form, (i.e.
country name will be added to mailing addresses and international prefixes added to phone numbers). The member
function ``acquire'' is used for asking an operator to enter address data. Note that the destructor is virtual, but not
pure virtual (what would happen if it was?)

Unselfish protection
All kinds of mailing addresses will share a base, inheriting from ``Address'', that contains the address fields, and
ways to access them. This class, however, will not implement any of the formatting pure virtuals from ``Address.''
That must be done by the concrete address classes with knowledge about the country's formatting and naming. The
member function ``type'' will be defined here, however, to always return the string ``Mailing address'', since all
kinds of mailing addresses are mailing addresses, even if they're Swedish addresses or U.S. Addresses. Access to the
address fields is for the concrete classes only, and this is a problem. We've seen how we can make things generally
available by declaring them public, or by hiding them from the general public by making them private. Here we
want something in between. We want descendants, the concrete address classes, to access the address fields, but
only the descendants and no one else. This can be achieved through the third protection level, ``protected.'' Protected
means that access is limited to the class itself (of course) and all descendants of it. It is thus looser than private, but
much stricter than public.
Here comes the ``MailingAddress'' base class:
class MailingAddress : public Address
{
public:
virtual ~MailingAddress();
const char* type() const;
protected:
MailingAddress();

void name(const char*); // set


const char* name() const; // get

void street(const char*); // set


const char* street() const; // get

void number(const char*); // set


const char* number() const; // get

void city(const char*); // set


const char* city() const; // get

void postalCode(const char*); // set


const char* postalCode() const; // get

void country(const char*); // set


const char* country() const; // get
private:
char* name_data;
char* street_data;
char* number_data;
char* city_data;
char* postalCode_data;
char* country_data;
//
// declared private to disallow them
//
MailingAddress(const MailingAddress&);
MailingAddress& operator=(const MailingAddress&);
};
Here the copy constructor and assignment operator is declared private to disallow copying and assignment. This is
not because they conceptually don't make sense, but because I'm too lazy to implement them (and yet want
protection from stupid mistakes that would come, no doubt, if I left it to the compiler to generate them). It's the
responsibility of this class to manage memory for the data strings, distributing this to the concrete descendants is
asking for trouble. As a rule of thumb, protected data is a bad mistake. Having all data private, and always manage
the resources for the data in a controlled way, and giving controlled access through protected access member
functions will drastically cut down your aspirin consumption.
The reason for the constructor to be protected is more or less just aestethical. No one but descendants can construct
objects of this class anyway, since some of the pure virtuals from ``Address'' aren't yet terminated.
Now we get to the concrete address classes:

class SwedishAddress : public MailingAddress


{
public:
SwedishAddress();
virtual void print(int international=0) const;
virtual void acquire(void);
};

class USAddress : public MailingAddress


{
public:
USAddress();
virtual void print(int international=0) const;
virtual void acquire(void);
};
As you can see, the definitions of ``USAddress'' and ``SwedishAddress'' are identical. The only difference lies in the
implementation of ``print'', and ``acquire''. I've left the destructors to be implemented at the compilers discretion.
Since there's no data to take care of in these classes (it's all in the parent class) we don't need to do anything special
here. We know the parent takes care of it. Don't be afraid of copy construction and assignment. They were declared
private in ``MailingAddress'', which means the compiler cannot create them the ``USAddress'' and
''SwedishAddress.''
Let's look at the implementation. For the ``Address'' base class only one thing needs implementing and that is the
destructor. Since the class holds no data, the destructor will be empty:

Address::~Address()
{
}
A trap many beginners fall into is to think that since the destructor is empty, we can save a little typing by declaring
it pure virtual and there won't be a need to implement it. That's wrong, though, since the destructor will be called
when a descendant is destroyed. There's no way around that. If you declare it pure virtual and don't implement it,
you'll probably get a nasty run-time error when the first concrete descendant is destroyed.
The observant reader might have noticed a nasty pattern of the authors refusal to get to the point with pure virtuals
and implementation. Yes, you can declare a member function pure virtual, and yet implement it! Pure virtual does
not illegalize implementation. It only means that the pure virtual version will NEVER be called through virtual
dispatch (i.e. by just calling the function on an object, a reference or a pointer to an object.) Since it will never, ever,
be called through virtual dispatch, it must be implemented by the descendants, hence the rule that you cannot
instantiate objects where pure virtuals are not terminated. By termination, by the way, I mean declaring it in a non
pure virtual way. OK, so a pure virtual won't ever be called through virtual dispatch. Then how can one be called?
Through explicit qualification. Let's assume, just for the sake of argument, that we through some magic found a way
to implement the some reasonable generic behaviour of ``acquire'' in ``Address,'' but we want to be certain that
descendants do implement it. The only way to call the implementation of ``acquire'' in ``Address'' is to explicitly
write ``Address::acquire.'' This is what explicit qualification means. There's no escape for the compiler; writing it
like this can only mean one thing, even if ``Address::acquire'' is declared pure virtual.
Now let's look at the middle class, the ``MailingAddress'' base class.

MailingAddress::~MailingAddress()
{
delete[] name_data;
delete[] street_data;
delete[] number_data;
delete[] city_data;
delete[] postalCode_data;
delete[] country_data;
}
I said when explaining the interface for this class, that it is responsible for handling the resources for the member
data. Since we don't know the length of the fields, we oughtn't restrict them, but rather dynamically allocate
whatever is needed. The ``delete[]'' syntax is for deleting arrays as opposed to just ``delete'' which deletes single
objects. Note that it's legal to delete the 0 pointer. This is used here. If, for some reason, one of the fields are not set
to anything, it will be 0. Deleting the 0 pointer does nothing at all. From this to the constructor:

MailingAddress::MailingAddress()
: name_data(0),
street_data(0),
number_data(0),
city_data(0),
postalCode_data(0),
country_data(0)
{
}
The only thing the constructor does is to make sure all pointers are 0, in order to guarantee destructability.
The ``type'' and read-access methods are trivial:

const char* MailingAddress::type(void) const


{
return "Mailing address";
}

const char* MailingAddress::name(void) const


{
return name_data;
}

const char* MailingAddress::street(void) const


{
return street_data;
}

const char* MailingAddress::number(void) const


{
return number_data;
}

const char* MailingAddress::city(void) const


{
return city_data;
}

const char* MailingAddress::postalCode(void) const


{
return postalCode_data;
}

const char* MailingAddress::country(void) const


{
return country_data;
}
The write access methods are a bit trickier, though. First we must check if the source and destination are the same,
and do nothing in those situations. This is to achieve robustness. While it may seem like a very stupid thing to do,
it's perfectly possible to see something like:

name(name());
The meaning of this is, of course, ``set the name to what it currently is.'' We must make sure that doing this works
(or find a way to illegalize the construct, but I can't think of any way). If the source and destination are different,
however, the old destination must be deleted, a new one allocated on heap and the contents copied. Like this:

void MailingAddress::name(const char* n)


{
if (n != name_data) {
delete[] name_data; // OK even if 0
name_data = new char[strlen(n)+1];
strcpy(name_data,n);
}
}
This is done so many times over and over, exactly the same way for all kinds of data members, that we'll use a
convenience function, ``replace,'' to do the job. ``strlen'' and ``strcpy'' are the C library functions from <string> that
calculates the length of, and copies strings.

static void replace(char*& data, const char* n)


{
if (data != n) {
delete[] data;
data = new char[strlen(n)+1];
strcpy(data,n);
}
}
Using this convenience function, the write-access member functions will be fairly straight forward:

void MailingAddress::name(const char* n)


{
::replace(name_data,n);
}

void MailingAddress::street(const char* n)


{
::replace(street_data,n);
}

void MailingAddress::number(const char* n)


{
::replace(number_data,n);
}

void MailingAddress::city(const char* n)


{
::replace(city_data,n);
}

void MailingAddress::postalCode(const char* n)


{
::replace(postalCode_data,n);
}

void MailingAddress::country(const char* n)


{
::replace(country_data,n);
}
That was all the ``MailingAddress'' base class does. Now it's time for the concrete classes. All they do is to ask
questions with the right terminology and output the fields in the right places:

SwedishAddress::SwedishAddress()
: MailingAddress()
{
country("Sweden"); // what else?
}

void SwedishAddress::print(int international) const


{
cout << name() << endl;
cout << street() << ' ' << number() << endl;
cout << postalCode() << ' ' << city() << endl;
if (international) cout << country() << endl;
}

void SwedishAddress::acquire(void)
{
char buffer[100]; // A mighty long field

cout << "Name: " << flush;


cin.getline(buffer,sizeof(buffer));
name(buffer);

cout << "Street: " << flush;


cin.getline(buffer,sizeof(buffer));
street(buffer);

cout << "Number: " << flush;


cin.getline(buffer,sizeof(buffer));
number(buffer);

cout << "Postal code: " << flush;


cin.getline(buffer,sizeof(buffer));
postalCode(buffer);

cout << "City: " << flush;


cin.getline(buffer,sizeof(buffer));
city(buffer);
}

USAddress::USAddress()
: MailingAddress()
{
country("U.S.A."); // what else?
}

void USAddress::print(int international) const


{
cout << name() << endl;
cout << number() << ' ' << street() << endl;
cout << city() << ' ' << postalCode() << endl;
if (international) cout << country() << endl;
}

void USAddress::acquire(void)
{
char buffer[100]; // Seems like a mighty long field

cout << "Name: " << flush;


cin.getline(buffer,sizeof(buffer));
name(buffer);

cout << "Number: " << flush;


cin.getline(buffer,sizeof(buffer));
number(buffer);

cout << "Street: " << flush;


cin.getline( buffer,sizeof(buffer));
street(buffer);

cout << "City: " << flush;


cin.getline(buffer, sizeof(buffer));
city(buffer);

cout << "State and ZIP: " << flush;


cin.getline(buffer,sizeof(buffer));
postalCode(buffer);
}

A toy program
Having done all this work with the classes, we must of course play a bit with them. Here's an short and simple
example program that (of course) also makes use of the generic programming paradigm introduced last month.

int main(void)
{
const unsigned size=10;
Address* addrs[size];
Address** first = addrs; // needed for VACPP (bug?)
Address** last = get_addrs(addrs,addrs+size);

cout << endl << "--------" << endl;


for_each(first,last,print(1));
for_each(first,last,deallocate<Address>());
return 0;
}
OK, that was mean. Obviously there's a function ``get_addrs'', which reads addresses into a range of iterators (in this
case pointers in an array) until the array is full, or it terminates for some other reason. Here's how it may be
implemented:

Address** get_addrs(Address** first,Address** last)


{
Address** current = first;
while (current != last)
{
cout << endl << "Kind (U)S, (S)wedish or (N)one "
<< flush;

char answer[5]; // Should be enough.


cin.getline(answer,sizeof(answer));
if (!cin) break;

switch (answer[0]) {
case 'U': case 'u':
*current = new USAddress;
break;
case 'S': case 's':
*current = new SwedishAddress;
break;
default:
return current;
}
(**current).acquire();
++current;
}
return current;
}
In part 6 I mentioned that virtual dispatch could replace switch statements, and yet here is one. Could this one be
replaced with virtual dispatch as well? It would be unfair of me to say ``no'', but it would be equally unfair of me to
propose using virtual dispatch here. The reason is that we'd need to work a lot without gaining anything. Why? We
obviously cannot do virtual dispatch on the ``Address'' objects we're about to create, since they're not created yet.
Instead we'd need a set of address creating objects, which we can access through some subscript or whatever, and
call a virtual creation member function for. Doesn't seem to save a lot of work does it? Probably the selection
mechanism for which address creating object to call would be a switch statement anyway!
So, that was reading, now for the rest. ``for_each'' does something for every iterator in a range. It could be
implemented like this:

template <class OI,class F>


void for_each(OI first,OI last, const F& functor)
{
while (first != last) {
functor(*first);
++first;
}
}
In fact, in the (final draft) C++ standard, there is a beast called ``for_each'' and behaving almost like this one (it
returns the functor). It's pretty handy. Imagine never again having to explicitly loop through a complete collection
again.
What is ``print'' then? Print is a ``functor,'' or ``function object'' as they're often called. It's something which behaves
like a function, but which might store a state of some kind (in this case whether the country should be added to
written addresses or not), and which can be passed around like any object. Defining one is easy, although it looks
odd at first.
class print
{
public:
print(int i) ;
void operator()(const Address*) const;
private:
int international;
};

print::print(int i)
: international(i)
{
}

void print::operator()(const Address* p) const


{
p->print(international);
cout << endl;
}
What on earth is ``operator()''? It's the member function that's called if we boldly treat the name of an object just as
if it was the name of some function, and simply call it. Like this:

print pobject; // define print object.


pobject(1); // pobject.operator()(1);
This is usually called the ``function call'' operator, by the way. The only remaining thing now is ``dealllocate<T>'',
but you probably already guessed it looks like this:

template <class T>


class deallocate
{
public:
void operator()(T* p) const;
};

template <class T>


void deallocate<T>::operator()(T* p) const
{
delete p;
}
This is well enough for one month, isn't it? You know what? You know by now most of the C++ language, and have
some experience with the C++ standard class library. Most of the language issues that remain are more or less
obscure and little known. We'll look mostly at library stuff and clever ideas for how to use the language from now
on.

Recap
This month, you've learned:
• what pure virtual means, and how you declare pure virtual functions.
• that despite what most C++ programmers believe, pure virtual functions can be implemented.
• that the above means that there's a distinction between terminating a pure virtual, and implementing one.
• why it's a bad idea to make destructors pure virtual.
• a new protection level, ``protected.''
• why protected data is bad, and how you can work around it in a clever way.
• that switch statements cannot always be replaced by virtual dispatch.
• that there is a ``function call'' operator and how to define and use it.

Exercises
• Find out what happens if you declare the ``MailingAddress'' destructor pure virtual, and yet define it.
• Think of two ways to handle the State/Zip problem, and implement both (what are the advantages,
disadvantages of the methods?)
• Rewrite ``get_addrs'' to accept templatized iterators instead of pointers.
Coming up
As I mentioned just a few lines above, most of the C++ language is covered. Quite a bit of the library remains, and
lots of useful and cool techniques are waiting to be exploited. Here's something for you to think about destructor,
pointer and delete. Anyway, next month we'll look at file I/O (finally). /Björn

Part Part Part Part Part Part Part Part Part Part1 Part1 Part1 Part1
1 2 3 4 5 6 7 8 9 0 1 2 3
In parts 5 and 6, the basics of I/O were introduced, with formatted reading and writing from standard input and
output. We'll now have a look at I/O for files. In a sense, it's better to stop using the term I/O here, and instead use
streams and streaming, since the ideas expressed here and in parts 5 and 6 can be used for other things than I/O, for
example in-memory formatting of data (we'll see that at the very end of this article.)

Files
In what way is writing ``Hello world'' on standard output different from writing it to a file? The question is worth
some thought, since in many programming languages there is a distinct difference. Is the message different? Is the
format (as seen from the program) different? I cannot see any difference in those aspects. The only thing that truly
differs is the media where the formatted message ends up. In the former case, it's on your screen, but for file I/O it's
in a file somewhere on your hard disk. In other words, there is very little difference, or at least, there's very much in
common.
As we've seen so far, commonality is expressed either through inheritance or templates, depending on what's
common and what's not. To refresh your memory, templates are used when we want the same kind of behaviour,
independent of data. For example a stack of some data type. Inheritance is used when you want similar, but in some
important aspects different, behaviour at runtime for the same kind of data. We saw this for the staff hierarchy and
mailing addresses in parts 7 and 8. In this case it's inheritance that's the correct solution, since the data will be the
same, but where it will end up (and most notably, how it does end up there) differs. (Incidentally, there's a good case
for using templates too, regarding the type of characters used. The C++ standard does indeed have templatized
streams, just for differing between character types. Few compilers today support this, however. See the ``Standards
Update'' towards the end of the article for more information.)
The inheritance tree for stream types look like this:

The way to read this is that there's a base class named ``ios'', from which the classes ``istream'' and ``ostream''
inherit. The classes ``ifstream'' and ``ofstream'' in their turn inherit from ``istream'' and ``ostream'' respectively. The
``f'' in the names imply that they're file streams. Then there's the odd ones, ``iostream'', which inherits from both
``istream'' and ``ostream'', and ``fstream'' which inherits from both ``ifstream'' and ``ofstream.'' Inheriting from two
bases is called multiple inheritance, and is by many seen as evil. Many programming languages have banned it:
Objective-C, Java, Smalltalk to mention a few, while other programming languages, like Eiffel, go to the other
extreme and allow you to inherit the same base several times Personally I think multiple inheritance is very useful if
used right, but it can cause severe problems. Here is a situation where it's used in the right way. Anyway, this means
that ``fstream'' is a file stream for both reading and writing, while ``iostream'' is an abstract stream for both reading
and writing. More often than you think, you probably don't want to use the ``iostream'' or ``fstream'' classes.
This inheritance, however, means that all the stream insertion and extraction functions (the ``operator>>'' and
``operator<<'') you've written, will work just as they do with file streams. Now, wasn't that neat? In other words, the
only things you need to learn for file based I/O are the details that are specific to files.

File Streams
The first thing you need to know before you can use file streams is how to create them. The parts of interest look
like this:

class ifstream : public istream


{
ifstream();
ifstream(const char* name,
int mode=ios::in);
void open(const char* name,
int mode=ios::in);
...
};

class ofstream : public ostream


{
ofstream();
ofstream(const char* name,
int mode=ios::out);
void open(const char* name,
int mode=ios::out);
...
};

class fstream : public ofstream, public ifstream


{
fstream();
fstream(const char* name,
int mode);
void open(const char* name,
int mode);
...
};
You get access to the classes by #including <fstream.h>. The empty constructors always create a file stream object
that is not tied to any file. To tie such an object to a file, a call to ``open'' must be made. ``open'' and the constructors
with parameters behaves identically. ``name'' is of course the name of the file. Since you normally use either
``ifstream'' or ``ofstream'' and rarely ``fstream'', this is normally the only parameter you need to supply. Sometimes,
however, you need to use the ``mode'' parameter. It's a bit field, in which you use bitwise or (``operator|'') for any of
the values ``ios::in'', ``ios::out'', ``ios::ate'', ``ios::app'', ``ios::trunc'', and finally ``ios::binary.'' Some implementations
also provide ``ios::nocreate'' and ``ios::noreplace,'' but those are extensions. Some implementations do not have
``ios::binary,'' while others call it ``ios::bin.'' These variations of course makes it difficult to write portable C++
today. Fortunately, the six ones listed first are required by the standard (although, they belong to class ``ios_base,''
rather than ``ios.'') The meaning of these are:

ios::in open for reading

ios::out open for writing

ios::ate open with the get and set pointer at the end
(see Seeking for info) of the file.

ios::app open for append, that is, any write you make
to the file will be appended to the file.

ios::trunc scrap all data in the file if it already exists.


ios::binary open in binary mode, that is, do not do the brain
damaged LF<->CR/LF conversions that OS/2,
DOS, CP/M (RIP), Windows, and probably other
operating systems, so often insist on. The reason
some implementations do not have ios::binary
is that many operating systems do not have this
conversion, so there's no need for it.

ios::noreplace cause the open to fail if the file already exists.

ios::nocreate cause the open to fail if the file doesn't exist.


Of course combinations like ``ios::noreplace | ios::nocreate'' doesn't make sense -- the failure is guaranteed.
On many implementations today there's also a third parameter for the constructors and ``open;'' a protection
parameter. How this parameter behaves is very operating system dependent.
Now for some simple usage:

#include <fstream.h>

int main(int argc, char* argv[])


{
if (argc != 2) {
cout << ``Usage: `` << argv[0] << ``filename'' << endl;
return 1; // error code
}

ofstream of(argv[1]); // create the ofstream object


// and open the file.

if (!of) { // something went wrong


cout << ``Error, cannot open `` << argv[1] << endl;
return 2;
}

// Now the file stream object is created. Write to it!


of << ``Hello file!'' << endl;
return 0;
}
As you can see, once the stream object is created, its usage is analogous to that of ``cout'' that you're already familiar
with. Of course reading with ``ifstream'' is done the same way, just use the object as you've used ``cin'' earlier.
The file stream classes also have a member function ``close'', that by force closes the file and unties the stream
object from it. Few are the situations when you need to call this member function, since the destructors do close the
file.
Actually this is all there is that's specific to files.

Binary streaming
So far we've dealt with formatted streaming only, that is, the process of translating raw data into a human readable
form, or translating human readable data into the computer's internal representation. Some times you want to stream
raw data as raw data, for example to save space in a file. If you look at a file produced by, for example a word
processor, it's most likely not in a human readable form. Note that binary streaming does not necessarily mean using
the ``ios::binary'' mode when opening a file (although, that is indeed often the case.) They're two different concepts.
Binary streaming is what you use your stream for, raw data that is, and opening a file with the ``ios::binary'' mode,
means turning the brain damaged LF<->CR/LF translation off.
Binary streaming is done through the stream member functions :

class ostream ...


{
public:
ostream& write(const char* s, streamsize n);
ostream& put(char c);
ostream& flush();
...
};

class istream ...


{
public:
istream& read(char* s, streamsize n);
int get();
istream& get(char& c);
istream& get(char* s, streamsize n, char delim='\n');
istream& getline(char* s, streamsize n,
char delim='\n');
istream& ignore(streamsize n=1, int delim=EOF);
};
The writing interface is extremely simple and straight forward, while the reading interface includes a number of
small but important differences. Note that these member functions are implemented in classes ``istream'' and
``ostream,'' so they're not specific to files, although files are where you're most likely to use them. Let's have a look
at them, one by one:

ostream& ostream::write(const char* s, streamsize n);


Write ``n'' characters to the stream, from the array pointed to by ``s.'' ``streamsize'' is a signed integral data type.
Despite ``streamsize'' being signed, you're of course not allowed to pass a negative size here (what would that
mean?) Exactly the characters found in ``s'' will be written to the stream, no more, no less.

ostream& ostream::put(char c);


Inserts the character into the stream.

ostream& ostream::flush();
Force the data in the stream to be written (file streams are usually buffered.)

istream& istream::read(char* s, streamsize n);


Read ``n'' characters into the array pointed to by ``s.'' Here you better make sure that the array is large enough, or
unpleasant things will happen. Note that only the characters read from the stream are inserted into the array. It will
not be zero terminated, unless the last character read from the stream indeed is '\0'.

int istream::get();
Read one character from the stream, and return it. The value is an ``int'' instead of ``char'' since the return value
might be ``EOF'' (which is not uniquely representable as a ``char.'')

istream& istream::get(char& c);


Same as above, but read the character into ``c'' instead. Here a ``char'' is used instead of an ``int,'' since you can
check the value directly by calling ``.eof()'' on the reference returned.

istream& istream::get(char* s, streamsize n,


char delim='\n');
This one's similar to ``read'' above, but with the difference that it reads at most ``n'' characters. It stops if the
delimiter character is found. Note that when the delimiter is found, it is not read from the stream.

istream& istream::getline(char* s, streamsize n,


char delim='\n');
The only difference between this one and ``get'' above, is that this one does read the delimiter from the stream. Note,
however, that the delimiter is not stored in the array.

istream& istream::ignore(streamsize n=1,


int delim=EOF);
Reads at most ``n'' characters from the stream, but doesn't store them anywhere. If the delimiter character is read, it
stops there. Of course, if the delimiter is ``EOF'' (as is the default) it does not read past ``EOF,'' that's physically
impossible.
Array on file
An example: Say we want to store an array of integers in a file, and we want to do this in raw binary format.
Naturally we want to be able to read the array as well. A reasonable way is to first store a size (in elements)
followed by the data. Both the size and the data will be in raw format.

#include <fstream.h>

void storeArray(ostream& os, const int* p, size_t elems)


{
os.write((const char*)&elems,sizeof(elems));
os.write((const char*)p, elems*sizeof(*p));
}
The above code does a lot of ugly type casting, but that's normal for binary streaming. What's done here is to use
brute force to see the address of ``elems'' as a ``const char*'' (since that's what ``write'' expects) and then say that
only the ``sizeof(elems)'' bytes from that pointer are to be read. What this actually does is to write out the raw
memory that ``elems'' resides in to the stream. After this, it does the same kind of thing for the array. Note that
``sizeof(*p)'' reports the size of the type that ``p'' points to. I could as well have written ``sizeof(int),'' but that is a
dangerous duplication of facts. It's enough that I've said that ``p'' is a pointer to ``int.'' Repeating ``int'' again just
means I'll forget to update one of them when I change the type to something else.
To read such an array into memory requires a little more work:

#include <fstream.h>

size_t readArray(istream& is, int*& p)


{
size_t elems;
is.read((char*)&elems, sizeof(elems));
p = new int[elems];
is.read((char*)elems, elems*sizeof(*p));
return elems;
}
It's not particularly hard to follow; first read the number of elements, then allocate an array of that size, and read the
data into it.

Seeking
Up until now we have seen streams as, what it sounds like, continuous streams of data. Sometimes however, there's
a need to move around, both backward and forward. Streams like standard input and standard output are truly
continuous streams, within which you cannot move around. Files, in contrast, are true random access data stores.
Random access streams have something called position pointers. They're not to be confused with pointers in the
normal C++ sense, but it's something referring to where in the file you currently are. There's the put pointer, which
refers to the next position to write data to, if you attempt to write anything, and the get pointer, which refers to the
next position to read data from. An ostream of course only has the put pointer, and an istream only the get pointer.
There's a total of 6 new member functions that deal with random access in a stream:

streampos istream::tellg();

istream& istream::seekg(streampos);

istream& istream::seekg(streamoff, ios::seek_dir);

streampos ostream::tellp();

ostream& ostream::seekp(streampos);

ostream& ostream::seekp(streamoff, ios::seek_dir);


``streampos'', which you get from ``tellg'' and ``tellp'' is an absolute position in a stream. You cannot use the values
for anything other than ``seekg'' and ``seekp''. You especially cannot examine a value and hope to find something
useful there (i.e. you can, but what you find out might hold only for the current release of your specific compiler,
other compilers, or other releases of the same compiler, might show different characteristics for ``streampos.'') Well,
there are two other things you can do with ``streampos'' values. You can subtract two values, and get a ``streamoff''
value, and you can add a ``streamoff'' value to a ``streampos'' value. ``streamoff,'' by the way, is some signed
integral type, probably a ``long.''
By using the value returned from ``tellg'' or ``tellp,'' you have a way of finding your way back, or do relative
searches by adding/subtracting ``streamoff'' values.
The ``seekg'' and ``seekp'' methods accept a ``streamoff'' value and a direction, and work in a slightly different way.
You search your way to a position relative to the beginning of the stream, the end of the stream, or the current
position, the selection of which, is done through the ``ios::seek_dir'' enum, which has these three values ``ios::beg'',
``ios::end'' and ``ios::cur.'' To make the next write occur on the very first byte of the stream, call
``os.seekp(0,ios::beg),'' where ``os'' is some random access ``ostream.''
In any reasonable implementation, any of the seek member functions use lazy evaluation. That is, when you call any
of the seek member functions, the only thing that happens is that some member variable in the stream object changes
value. It's not until you actually read or write, something truly happens on disk (or wherever the stream data resides.)

A stream array, for really huge amounts of data


Suppose we have a need to access enormous amounts of simple data, say 10 million floating point numbers. It's not
a very good idea to just allocate that much memory, at least not on my machine with a measly 64Mb RAM. It'll not
just make this application crawl, but probably the whole system due to excessive paging. Instead, let's use a file to
access the data. This makes for slow access, for sure, but nothing else will suffer.
Here's the idea. The array must be possible to use with any data type, including user defined classes. Its usage must
resemble that of real arrays as much as possible, but extra functionality that arrays do not have, such as asking for
the number of elements in it, is OK. There must be a type, resembling pointers to arrays, that can be used for
traversing it. We do not want the size of the array to be part of its type (if you've programmed in Pascal, you know
why.) In addition to arrays, we want some measures of safety from stupid mistakes, such as addressing beyond the
range of the array, and also for errors that arrays cannot have (disk full, cannot create file, disk corruption, etc.) We
also want to say that an array is just a part of a file and not necessarily an entire file. This would allow the user to
create several arrays within the same file. To prevent this article from growing way too long, quite a few of the
above listed features will be left for next month. The things to cover this month are: An array of built-in fundamental
types only, which lacks pointers and is limited to one file per array. We'll also skip error handling for now (you can
add it as an exercise, I'll raise some interesting questions along the way,) and add that too next month.
First of all, the array must be a template, so it can be used to store arbitrary types. Since we do not want the size to
be part of the type signature, the size is not a template parameter, but a parameter for the constructor. Of course, we
cannot have the entire array duplicated in memory (then all the benefits will be lost,) instead we will search for the
data on file every time it's needed.
Here's the outline for the class.

template <class T>

class FileArray
{
public:
FileArray(const char* name, size_t elements);
// Create a new array and set the size.

FileArray(const char* name);


// Create an array from an existing file, get the
// size from the file.

// use compiler defined destructor.

T operator[](size_t index) const;


??? operator[](size_t index);

size_t size() const;


private:
// don't want these to be used.
FileArray(const FileArray&);
FileArray& operator=(const FileArray&);
...
};
As can be expected, ``operator[]'' can be overloaded, which is handy for providing a familiar syntax. However,
already here we see a problem. What's the non-const ``operator[]'' to return? To see why this is a problem, ask
yourself what you want ``operator[]'' to do. I want ``operator[]'' to do two things, depending on where it's used; like
this:

FileArray<int> x;
...
x[5] = 4;
int y = x[3];
When ``operator[]'' is on the left hand side of an assignment, I want to write data to the file, and if its on the right
hand side of an assignment, I want to read data from the file. Ouch.
Warning: I've often seen it suggested that the solution is to have the const version read and return a value, and the
non-const version write a value. As slick as it would be, it's wrong and it won't work. The const version is called for
const array objects, the non-const version for non-const array objects.
Instead what we have to do is to pull a little trick. The trick is, as so often in computer science, to add another level
of indirection. This is done by not taking care of the problem in ``operator[],'' but rather let it return a type, which
does the job. We create a class template, looking like this:

template <class T>


class FileArrayProxy
{
public:
FileArrayProxy<T>& operator=(const T&); // write value
operator T() const; // read a value

// compiler generated destructor

FileArrayProxy<T>&
operator=(const FileArrayProxy<T>& p);

FileArrayProxy(const FileArrayProxy<T>&);
private:
... all other constructors.
FileArray<T>& array;
const size_t index;
};
We have to make sure, of course, that there are member functions in ``FileArray<T>'' that can read and write (and of
course, those functions are not the ``operator[],'' since then we'd have an infinite recursion.) All constructors, except
for the copy constructors, are made private to prevent users from creating objects of the class whenever they want
to. After all, this class is a helper for the array only, and is not intended to ever even be seen. This, however, poses a
problem; with the constructors being private, how can ``FileArray<T>::operator[]()'' create and return one?
Enter another C++ feature: friends. Friends are a way of breaking encapsulation. What?!?! Yes, what you read is
right. Friends break encapsulation, and (this is the real shock) that's a good thing! Friends break encapsulation in a
controlled way. We can, in ``FileArrayProxy<T>'' declare ``FileArray<T>'' to be a friend. This means that
``FileArray<T>'' can access everything in ``FileArrayProxy<T>,'' including things that are declared private.
Paradoxically, violating encapsulation with friendship strengthens encapsulation when done right. The only
alternative here to using friendship, is to make the constructors public, but then anyone can create objects of this
class, and that's what we wanted to prevent. Friends are useful for strong encapsulation, but it's important to use it
only in situations where two (or more classes) are so tightly bound to one another that they're meaningless on their
own. This is the case with ``FileArrayProxy<T>.'' It's meaningless without ``FileArray<T>,'' thus ``FileArray<T>'' is
declared a friend of ``FileArrayProxy<T>.'' The declaration then becomes:

template <class T>

class FileArrayProxy
{
public:
FileArrayProxy& operator=(const T&); // write a value
operator T() const; // read a value
// compiler generated destructor

FileArrayProxy<T>& // read from p and then write


operator=(const FileArrayProxy<T>& p);
// compiler generated copy contructor
private:
FileArrayProxy(FileArray<T>& fa, size_t n);
// for use by FileArray<T> only.

FileArray<T>& array;
const size_t index;

friend class FileArray<T>;


};
We can now start implementing the array. Some problems still lie ahead, but I'll mention them as we go.

// farray.hpp
#ifndef FARRAY_HPP
#define FARRAY_HPP

#include <fstream.h>
#include <stdlib.h> // size_t

template <class T> class FileArrayProxy;


// Forward declaration necessary, since FileArray<T>
// returns the type.

template <class T> class FileArray


{
public:
FileArray(const char* name, size_t size); // create
FileArray(const char* name); // use existing array
T operator[](size_t size) const;
FileArrayProxy<T> operator[](size_t size);
size_t size() const;
private:
FileArray(const FileArray<T>&); // illegal
FileArray<T>& operator=(const FileArray<T>&);

// for use by FileArrayProxy<T>


T readElement(size_t index) const;
void storeElement(size_t index, const T&);

fstream stream;
size_t max_size;

friend class FileArrayProxy<T>;


};
The functions for reading and writing are made private members of the array, since they're not for anyone to use.
Again, we need to make use of friendship to grant ``FileArrayProxy<T>'' the right to access them. Let's define them
right away

template <class T>


T FileArray<T>::readElement(size_t index) const
{
T t;
stream.seekg(sizeof(max_size)+index*sizeof(T));
// what if seek fails?

stream.read((char*)&t, sizeof(t));
// what if read fails?

return t;
}
All of a sudden, we face an unexpected problem. The above code won't compile. The member function is declared
``const'', and as such, all member variables are ``const'', and neither ``seekg'' nor ``read'' are allowed on constant
streams. The problem is one of differing between logical constness and bitwise constness. This member function is
logically ``const'', as it does not alter the array in any way. However, it is not bitwise const; the stream member
changes. C++ cannot understand logical constness, only bitwise constness. If you have a modern compiler, the
solution is very simple; you declare ``stream'' to be ``mutable fstream stream;'' in the class definition. I, however,
have a very old compiler, so I have to find a different solution. This solution is, yet again, one of adding another
level of indirection. I can have a pointer to an ``fstream.'' When in a ``const'' member function, the pointer is also
``const'', but not what it points to (there's a difference between a constant pointer, and a pointer to a constant.) The
only reasonable way to achieve this is to store the stream object on the heap, and in doing this I introduce a possible
danger; what if I forget to delete the pointer? Sure, I'll delete it in the destructor, but what if an exception is thrown
already in the constructor, then the destructor will never execute (since no object has been created that must be
destroyed.)
Do you remember the ``thing to think of until this month?'' The clues were, destructor, pointer and delete. Thought
of anything? What about this extremely simple class template?

template <class T>


class ptr
{
public:
ptr(T* pt);
~ptr();

T& operator*() const;


private:
ptr(const ptr<T>&); // we don't want copying
ptr<T>& operator=(const ptr<T>&); // nor assignment

T* p;
};

template <class T>


ptr<T>::ptr(T* pt)
: p(pt)
{
}

template <class T>


ptr<T>::~ptr()
{
delete p;
}

template <class T>


T& ptr<T>::operator*() const
{
return *p;
}
This is probably the simplest possible of the family known as ``smart pointers.'' I'll probably devote a whole article
exclusively for these some time. Whenever an object of this type is destroyed, whatever it points to is deleted. The
only thing we have to keep in mind when using it, is to make sure that whatever we feed it is allocated on heap (and
is not an array) so it can be deleted with operator delete.
This solves our problem nicely. When this thing is a constant, the thing pointed to still isn't a constant (look at the
return type for ``operator*,'' it's a ``T&,'' not a ``const T&.'') So, instead of using an ``fstream'' member variable
called ``stream,'' let's use a ``ptr<stream>'' member named ``pstream.'' With this change, ``readElement'' must be
slightly rewritten:

template <class T>


T FileArray<T>::readElement(size_t index) const
{
(*pstream).seekg(sizeof(max_size)+index*sizeof(T));
// what if seek fails?

T t;
(*pstream).read((char*)&t, sizeof(t));
// what if read fails?

return t;
}
I bet the change wasn't too horrifying.

template <class T>


void FileArray<T>::storeElement(size_t index,
const T& elem)
{
(*pstream).seekp(sizeof(max_size)+index*sizeof(T),
ios::beg);
// what if seek fails?

(*pstream).write((char*)&elem, sizeof(elem));
// what if write failed?
}
Now for the constructors:

template <class T>


FileArray<T>::FileArray(const char* name, size_t size)
: pstream(new fstream(name, ios::in|ios::out|ios::binary)),
max_size(size)
{
// what if the file could not be opened?

// store the size on file.


(*pstream).write((const char*)&max_size,
sizeof(max_size));
// what if write failed?

// We want to write a value (any value) at the end


// to make sure there is enough space on disk.

T t;
storeElement(max_size-1,t);
// What if this fails?
}

template <class T>


FileArray<T>::FileArray(const char* name)
: pstream(new fstream(name, ios::in|ios::out|ios::binary)),
max_size(0)
{
// get the size from file.
(*pstream).read((char*)&max_size,
sizeof(max_size));
// what if read fails or max_size == 0?
// How do we know the file is even an array?
}
The access members:

template <class T>


T FileArray<T>::operator[](size_t size) const
{
// what if size >= max_size?
return readElement(size);
// What if read failed because of a disk error?
}

template <class T>


FileArrayProxy<T> FileArray<T>::operator[](size_t size)
{
// what if size >= max_size?
return FileArrayProxy<T>(*this , size);
}
Well, this wasn't too much work, but then, as can be seen by the comments, there's absolutely no error handling
here. I've left out the ``size'' member function, since its implementation is trivial.
Next in line is ``FileArrayProxy<T>.''

template <class T>


class FileArrayProxy
{
public:
// copy constructor generated by compiler
operator T() const;
FileArrayProxy<T>& operator=(const T& t);
FileArrayProxy<T>&
operator=(const FileArrayProxy<T>& p);
// read from one array and write to the other.
private:
FileArrayProxy(FileArray<T>& f, size_t i);

size_t index;
FileArray<T>& fa;

friend class FileArray<T>;


};
The copy constructor is needed, since the return value must be copied (return from ``FileArray<T>::operator[],'') and
it must be public for this to succeed. The one that the compiler generates for us, which just copies all member
variables, will do just fine. The compiler doesn't generate a default constructor (one which accepts no parameters,)
since we have explicitly defined a contructor. The assignment operator is necessary, however. Sure, the compiler
will try to generate one for us if we don't, but it will fail, since references (``fa'') can't be rebound. Note, however,
that if we instead of a reference had used a pointer, it would succeed, but the result would *NOT* be what we want.
What it would do is to copy the member variables, but what we want to do is to read data from one array and write it
to another.
Now for the implementation:

template <class T>


FileArrayProxy<T>::FileArrayProxy(FileArray<T>& f,
size_t i)
: index(i),
fa(f)
{
}

template <class T>


FileArrayProxy<T>::operator T() const
{
return fa.readElement(index);
}

template <class T>


FileArrayProxy<T>&
FileArrayProxy<T>::operator=(const T& t)
{
fa.storeElement(index,t);
return *this;
}

template <class T>


FileArrayProxy<T>& FileArrayProxy<T>::operator=(
const FileArrayProxy<T>& p
)
{
fa.storeElement(index,p);
return *this;
}

#endif // FARRAY_HPP
That was it. Can you see what happens with the proxy? Let's analyze a small code snippet:

1 FileArray<int> arr("file",10);
2 arr[2]=0;
3 int x=arr[2];
4 arr[0]=arr[2];
On line two, ``arr.operator[](2)'' is called, which creates a ``FileArrayProxy<int>'' from ``arr'' with the index 2. The
object, which is a temporary and does not have a name, has as its member ``fa'' a reference to ``arr'', and as its
member ``index'' the value 2. On this temporary object, ``operator=(int)'' is executed. This operator in turn calls
``fa.storeElement(index, t),'' where ``index'' is still 2 and the value of ``t'' is 0. Thus, ``arr[2]=0'' ends up as
``arr.storeElement(2,0)''. On line 3, a similar proxy is created through the call to ``operator[](2)'' This time, however,
the ``operator int() const'' is called. This member function in turn calls ``fa.readElement(2)'' and returns its value,
thus ``int x=arr[2]'' translates to ``int x=arr.readElement(2).'' On line 4, finally, ``arr[0]=arr[2]'' creates two
temporary proxies, one referring to index 0, and one to index 2. The assignment operator is called, which in turn
calls ``fa.storeElement(0,p)'', where p is the temporary proxy referring to element 2. Since ``storeElement'' wants an
``int,'' ``p.operator int() const'' is called, which calls ``arr.readElement(2).'' In other words ``arr[0] = arr[2]'' generates
the code ``arr.storeElement(0, arr.readElement(2)).''
As you can see, the proxies don't add any new functionality, they're just syntactic sugar, albeit very useful. With
them we can treat our file arrays very much like any kind of array. There's one thing we cannot do:

int* p = &arr[2];
int& x = arr[3];
*p=2;
x=5;
With ordinary arrays, the above would be legal and have well defined semantics, assigning arr[2] the value 2, and
arr[3] the value 5. With our file array we cannot do this, but unfortunately the compiler does not prevent it (a decent
compiler will warn that we're binding a constant or pointer to a temporary.) We'll mend that hole next month (think
about how) and also add iterators, which will allow us to use the file arrays almost exactly like real ones.

In memory data formatting


One often faced problem is that of converting strings representing some data to that data, or vice versa. With the aid
of ``istrstream'', ``ostrstream'' and ``strstream'', this is easy. For example, say we have a string containing digits, and
want those digits as an integer, the thing to do is to create an ``istrstream'' object from the string. An example will
explain:

char* s = "23542";
istrstream is(s);
int x;
is >> x;
After executing this snippet, ``x'' will have the value 23542. ``istrstream'' isn't much more exciting than that.
``ostrstream'' on the other hand is more exciting. There are two alternative uses for ``ostrstream.'' One where you
have an array you want to store data in, and one where you want the ``ostrstream'' to create it for you, as needed
(usually because you have no idea what size the buffer must have.) The former usage is like this:

char buffer[24];
ostrstream os(buffer, sizeof(buffer));
double x=23.34;
os << "x=" << x << ends;
The variable ``buffer'' will contain the string ``x=23.34'' after this snippet. The stream manipulator ``ends'' zero
terminates the buffer. Zero termination is not done by default, since the stream cannot know where to put it, and
besides you might not always want it.
The other variant, where you don't know how large a buffer you will need, is generally more useful (I think.)

ostrstream os;
double x=23.34, y=34.45;
os << x << '*' << y << '=' << x*y << ends;
const char* p = os.str();
const size_t length=os.pcount();

// work with p and length.


os.freeze(0); // release the memory.
I think the example pretty much shows what this kind of usage does. The member function ``str'' returns a pointer to
the internal buffer (which is then frozen, that is, the stream guarantees that it will not deallocate the buffer, nor
overwrite it. Attempts to alter the stream while frozen, will fail.) ``pcount'' returns the number of characters stored in
the buffer. Last ``freeze'' can either freeze the buffer, or ``unfreeze'' it. The latter is done by giving it a parameter
with the value 0. I find this interface to be unfortunate. It's so easy to forget to release the buffer (by simply
forgetting to call ``os.freeze(0)'') and that leads to a memory leak.
``strstream'' finally, is just like ``fstream'' the combined read/write stream.
The string streams can be found in the header <strstream.h> (or for some compilers <strstrea.h>.)

Standards update
With the C++ standard, a lot of things have changed regarding streams. As I mentioned already last month, the
headers are actually <iostream> and <fstream>, and the names std::istream, std::ostream, etc. The streams are
templatized too, which both makes life easier and not. The underlying type for std::ostream is:

std::basic_ostream<class charT,
class traits=std::char_traits<charT> >
``charT'' is the basic type for the stream. For ``ostream'' this is ``char'' (ostream is actually a typedef.) There's another
typedef, ``std::wostream'', where the underlying type is ``wchar_t'', which on most systems probably will be 16-bit
Unicode. The class template ``char_traits'' is a traits class which holds the type used for EOF, the value of EOF, and
some other house keeping things.
Why the standard has removed the file stream open modes ios::create and ios::nocreate is beyond me, as they're
extremely useful.
Casting is ugly, and it's hard to see in large code blocks. There are four new cast operators, that are highly visible, in
the standard. They're (in approximate order of increasing danger,) dynamic_cast<T>, static_cast<T>, const_cast<T>
and reinterpret_cast<T>. In the binary streaming seen in this article, reinterpret_cast<T> would be used, as a way of
saying, ``Yeah, I know I'm violating type safety, but hey, I know what I'm doing, OK?'' The good thing about it is
that it's so visible that anyone doubting it can easily spot the dangerous lines and have a careful look. The syntax is:
os.write(reinterpret_cast<const char*>(&variable), sizeof(variable));
Finally, the generally useful strstreams has been replaced by ``std::istringstream'', ``std::ostringstream'' and
``std::stringstream'' (plus wide variants, std::wistringstream, etc.) defined in the header <sstream>. They do not
operate on ``char*'', but on strings (there is a string class, or again, rather a string class template, where the most
important template parameter is the underlying character.) ``std::ostringstream'' does not suffer from the freeze
problem that ``ostrstream'' does.

Recap
The news this month were:
• streams dealing with files, or in-memory formatting, are used just the same way as the familiar ``cout'' and
``cin,'' which saves both learning and coding (the already written ``operator<<'' and ``operator>>'' can be
used for all kinds of streams already.)
• streams can be used for binary, unformatted I/O too. This normally doesn't make sense for ``cout'' and
``cin'' or in-memory formatting (as the name implies,) but it's often useful when dealing with files.
• It is possible to move around in streams, at least file streams and in-memory formatting streams. It's
generally not possible to move around in ``cin'' and ``cout.''
• proxy classes can be used to differentiate read and write operations for ``operator[]'' (the construction can of
course be used elsewhere too, but it's most useful in this case.)
• friends break encapsulation in a way that, when done right, strengthens encapsulation.
• there's a difference between logical const and bitwise const, but the C++ compiler doesn't know and always
assumes bitwise const.
• truly simple smart pointers can save some memory management house keeping, and also be used as a work
around for compilers lacking ``mutable'' (i.e. the way of declaring a variable as non-const for const
members, in other words, how to differentiate between logical and bitwise const.)
• streams can be used also for in-memory formatting of data.
Exercises
• Improve the file array such that it accepts a ``stream&'' instead of a file name, and allows for several arrays
in the same file.
• Improve the proxy such that ``int& x=arr[2]'' and ``int* p=&arr[1]'' becomes illegal.
• Add a constructor to the array that accepts only a ``size_t'' describing the size of the array, which creates a
temporary file and removes it in its destructor.
• What happens if we instantiate ``FileArray'' with a user defined type? Is it always desireable? If not, what is
desireable? If you cannot define what's desireable, how can instantiation with user defined types be
banned?
• How can you, using the stream interface, calculate the size of a file?

Coming up
Next month will be devoted to improving the ``FileArray.'' We'll have iterators, allow arbitrary types, add error
handling and more. I assume I won't need to tell you that it'll be possible to use the ``FileArray,'' just as ordinary
arrays with generic programming, i.e. we can have the exact same source code for dealing with both!

Part Part Part Part Part Part Part Part Part Part1 Part1 Part1 Part1
1 2 3 4 5 6 7 8 9 0 1 2 3
[Note: the source code for this month is here. Ed.]
Last month a file based array template for truly huge amounts of data was introduced. While good, it was nowhere
near our goals. Error handling was missing completely, making it dangerous to use in real life. There was no way to
say how a user defined data type should be represented on disk, yet they weren't disallowed, which is a dangerous
combination. It was also lacking iterators, something that is handy, and is an absolute requirement for generic
programming with algorithms that are independent of the source of the data. On top of that, we'd really like the
ability to store several different arrays in the same file, and also have an anonymous array which creates a temporary
file and removes it when the array is destroyed. All of these will be dealt with this month, yet very little will be new.
Instead it's time to make use of all the things learned so far in the course.

The data representation problem


In the file array as implemented last month, data was always stored in a raw binary format, exactly mirroring the bits
as they lay in memory. This works fine for integers and such, but can be disastrous in other situations. Imagine a file
array of strings (where string is a ``char*''). With the implementation from last month, the pointer value would be
stored, not the data pointed to. When reading, a pointer value is read, and when dereferenced, whatever happens to
be at the memory location pointed to (if anything) will be used (which is more than likely to result in a rather quick
crash.) Anything with pointers is dangerous when stored in a raw binary format, yet we must somehow allow
pointers in the array, and preferably so without causing problems for those using the array with built-in arithmetic
types. How can this be done?
In part 4, when templates were introduced, a clever little construct called ``traits classes'' was shown. I then gave this
rather terse description: ``A traits class is never instantiated, and doesn't contain any data. It just tells things about
other classes, that is its sole purpose.'' Doesn't that smell like something we can use here? A traits class that tells how
the data types should be represented on disk?
What do we need from such a traits class? Obviously, we need to know how much disk space each element will
take, so a ``size'' member will definitely be necessary, otherwise we cannot know much disk space will be required.
We also need to know how to store the data, and how to read it. The easiest way is probably to have member
functions ``writeTo'' and ``readFrom'' in the traits class. Thus we can have something looking like this:

template <class T> class FileArrayElementAccess


{
public:
static const size_t size;
static void writeTo(T value, ostream& os);
static T readFrom(istream& is);
};
The array is then rewritten to use this when dealing with the data. The change is extremely minor. ``storeElement''
needs to be rewritten as:

template <class T>


void FileArray<T>::storeElement(size_t index,
const T& element)
{
// what if index >= array_size?
typedef FileArrayElementAccess<T> traits;
(*pstream).seekp(traits::size*index
+sizeof(array_size), ios::beg);
// what if seek fails?
traits::writeTo(element,*pstream);
// what if write failed?
// what if too much data was written?
}
The change for ``readElement'' is of course analogous. However, as indicated by the last comment, a new error
possibility has shown up. What if the ``writeTo'' and ``readFrom'' members of the traits class are buggy and write or
read more data to disk than they're allowed to? Since it's the user of the array that must write the traits class (at least
for their own data types) we cannot solve the problem, but we can give the user a chance to discover that something
went wrong. Unfortunately for writing, the error is extremely severe; it means that the next entry in the array will
have its data destroyed...
In the traits class, by the way, the constant ``size'', used for telling how many bytes in the stream each ``T'' will
occupy, poses a problem with most C++ compilers today (modern ones mostly makes life so much easier.) The
problem is that a static variable, and also a static constant, in a class, needs to reside somewhere in memory, and the
class declaration is not enough for that. This problem is two-fold. To begin with, where should it be stored? It's very
much up to whoever writes the class, but somewhere in the code, there must be something like:

const size_t ArrayFileElementAccess<X>::size = ...;


where ``X'' is the name of the class dealt with by the particular traits specialisation.
The second problem is that this is totally unnecessary. What we want is a value that can be used by the compiler at
compile time, not a memory location to read a value from. As I mentioned, a modern compiler does make this much
easier. In standard C++ it is allowed to write:

template<> class ArrayFileElementAccess<X>


{
public:
const size_t size = ...;
...
};
Note that for some reason that I do not know, this construct is only legal if the type is a constant of an integral or
enumeration type. ``size_t'' is such a type, it's some unsigned integral type, probably ``unsigned int'', but possibly
``unsigned long''. The expression denoted ``...'' must be possible to evaluate at compile time. Unless code is written
that explicitly takes the address of ``size'', we need not give the constant any space to reside in. The odd construct
``template <>'' is also new C++ syntax, and means that what follows is a specialisation of a previously declared
template.
For old compilers, however, there's a work-around for integral values, no larger than the largest ``int'' value. We
cheat and use an enum instead of a ``size_t''. This makes the declaration:

class ArrayFileElementAccess<X>
{
public:
enum { size= ... };
...
};
This is a bit ugly, but it is perfectly harmless.
The advantage gained by adding the traits class is flexibility and safety. If someone wants to use a file array for their
own class, they're free to do so. However, they must first write a ``FileArrayElementAccess'' specialisation. Failure
to do so will result in a compilation error. This early error detection is beneficial. The sloppy solution from last
month would not yield any error until run-time, which means a (usually long) debugging session.

Several arrays in a file


What is needed in order to host several arrays in the same file? One way or the other, there must be a mechanism for
finding out where one array begins and another ends. I think the simplest solution, is to let go of the file names, and
instead make the constructors accept an ``fstream&''. We can then require that the put and get pointer of the stream
must be where the array can begin, and we can in turn promise that the put and get pointer will be positioned at the
byte after the array end. Of course, in addition to having a reference to the ``fstream'' in our class, we also need the
``home'' position, to seek relative to, when indexing the array. This becomes easy to write for us, it becomes easy to
use as well. For someone requiring only one array in a file, there'll be slightly more code, an ``fstream'' object must
be explicitly initialised somewhere, and passed to the constructor of the array, instead of just giving it a name. I
think the functionality increase/code expansion exchange is favorable.
In order to improve the likelihood of finding errors, we can waste a few bytes of disk space by writing a well known
header and trailer pattern at the beginning and end of the array (before the first element, and after the last one.) If
someone wants to allocate an array using an existing file, we can find out if the get pointer is in place for an array
start.
The constructor creating a file should, however, first try to read from the file to see if it exists. If it does, it should be
created from the file, just like the constructor accepting a stream only does. If the read fails, however, we can safely
assume that the file doesn't exist and should instead be created.
The change in the class definition, and constructor implementation is relatively straight forward, if long:

template <class T>


class FileArray
{
public:
FileArray(fstream& fs, size_t elements);
// create a new file.

FileArray(fstream& fs);
// use an existing file and get size from there
...
private:
void initFromFile(const char*);

fstream& stream;
size_t array_size; // in elements
streampos home;
};

template <class T>


FileArray<T>::FileArray(fstream& fs, size_t elements)
: stream(fs),
array_size(elements)
{
// what if the file could not be opened?
// first try to read and see if there's a begin
// pattern. Either there is one, or we should
// get an eof.

char pattern[6];
stream.read(pattern,6);
if (stream.eof()) {
stream.clear(); // clear error state
// and initialise.

// begin of array pattern.


stream.write("ABegin",6);
// must store size of elements, as last month
const size_t elem_size
=FileArrayElementAccess<T>::size;
stream.write((const char*)&elem_size,
sizeof(elem_size));
// and of course the number of elements
stream.write((const char*)&array_size,
sizeof(array_size));
// Now that we've written the maintenance
// stuff, we know what the home position is.

home = stream.tellp();
// Then we must go the the end and write
// the end pattern.

stream.seekp(home+elem_size*array_size);
stream.write("AEnd",4);

// set put and get pointer to past the end pos.


stream.seekg(stream.tellp());
return;
}

initFromFile(pattern); // shared with other


// stream constructor
if (array_size != elements) {
// Uh oh. The data read from the stream,
// and the size given in the constructor
// mismatches! What now?
stream.clear(ios::failbit);
}

// set put and get pointer to past the end pos.


stream.seekp(stream.tellg());
}

template <class T>


FileArray<T>::FileArray(fstream& fs)
: stream(fs)
{
// First read the head pattern to see if
// it's right.
char pattern[6];
stream.read(pattern,6);
initFromFile(pattern);
// set put and get pointer to past the end pos.
stream.seekp(stream.tellg());
}

template <class T>


void FileArray<T>::initFromFile(const char* p)
{
// Check if the read pattern is correct
if (strncmp(p,"ABegin",6)) {
// What to do? It was all wrong!
stream.clear(ios::failbit);
// for lack of better,
// set the fail flag.
return;
}
// OK, we have a valid array, now let's see if
// it's of the right kind.
size_t elem_size;
stream.read((char*)&elem_size,sizeof(elem_size));
if (elem_size != FileArrayElementAccess<T>::size)
{
// wrong kind of array, the element sizes
// mismatch. Again, what to do? Let's set
// the fail flag for now.
stream.clear(ios::failbit);
// stupid name for the
// member function, right?
return;
}
// Get the size of the array. Can't do much with
// the size here, though.
stream.read((char*)&array_size,sizeof(array_size));
// Now we're past the header, so we know where the
// data begins and can set the home position.

home = stream.tellg();

stream.seekg(home+elem_size*array_size);

// Now positioned immediately after the last


// element.

char epattern[4];
stream.read(epattern,4);
if (strncmp(epattern,"AEnd",4)) {
// Whoops, corrupt file!
stream.clear(ios::failbit);
return;
}
// Seems like we have a valid array!
}
Other than the above, the only change needed for the array is that seeking will be done relative to ``home'' rather
than the beginning of the file (plus the size of the header entries.) The new versions of ``storeElement'' and
``readElement'' become:

template <class T>


T FileArray<T>::readElement(size_t index) const
{ // what if index >= max_elements?
typedef FileArrayElementAccess<T> traits;
stream.seekg(home+index*traits::size);
// what if seek fails?

return traits::readFrom(stream);
// what if read fails?
// What if too much data is read?
}

template <class T>


void FileArray<T>::storeElement(size_t index,
const T& element)
{ // what if index >= array_size?
typedef FileArrayElementAccess<T> traits;
stream.seekp(home+traits::size*index);
// what if seek fails?
traits::writeTo(element,stream);
// what if write failed?
// what if too much data was written?
}

Temporary file array


Making use of a temporary file to store a file array that's not to be persistent between runs of the application isn't that
tricky. The implementation so far makes use of a stream and known data about the beginning of the stream, number
of elements and size of the elements. This can be used for the temporary file as well. The only thing we need to do is
to create the temporary file first, open it with an fstream object, and tie the stream reference to that object, and
remember to delete the file in the destructor.
What's the best way of creating something and making sure we remember to undo it later? Well, of course, creating
a new helper class which creates the file in its constructor and removes it in its destructor. Piece of cake. The only
problem is that we shouldn't always create a temporary file, and when we do, we can handle it a bit different from
what we do with a ``global'' file that can be shared. For example, we know that we have exclusive rights to the file,
and that it won't be reused, so there's no need for the extra information in the beginning and end. So, how's a
temporary file created? The C++ standard doesn't say, and neither is there any support for it in the old de-facto
standard. I don't think C does either. There are, however, two functions ``tmpnam'' and ``tempnam'' defined as
commonly supported extensions to C. They can be found in <stdio.h>. I have in this implementation chosen to use
``tempnam'' as it's more flexible. ``tempnam'' works like this: it accepts two string parameters named ``dir'' and
``prefix''. It first attempts to create a temporary file in the directory pointed to by the environment variable
``TMPDIR''. If that fails, it attempts to create it in the directory indicated by the ``dir'' parameter, unless it's 0, in
which case a hard-coded default is attempted. It returns a ``char*'' indicating a name to use. The memory area
pointed to is allocated with the C function ``malloc'', and thus must be deallocated with ``free'' and not delete[].
Over to the implementation details:
We add a class called temporaryfile, which does the above mentioned work. We also add a member variable ``pfile''
which is of type ``ptr<temporaryfile>''. Remember the ``ptr'' template from last month? It's a smart pointer that
deallocates whatever it points to in its destructor. It's important that the member variable ``pfile'' is listed before the
``stream'' member, since initialisation is done in the order listed, and the ``stream'' member must be initialised from
the file object owned by ``pfile''. We also add a constructor with the number of elements as its sole parameter, which
makes use of the temporary file.

class temporaryfile
{
public:
temporaryfile();
~temporaryfile();
iostream& stream();
private:
char* name;
fstream fs;
};

temporaryfile::temporaryfile()
: name(::tempnam(".","array")),
fs(name, ios::in|ios::out|ios::binary)
{
// what if tmpnam fails and name is 0
// what if fs is bad?
}

temporaryfile::~temporaryfile()
{
fs.close();
::remove(name);
// what if remove fails?
::free(name);
}
In the above code, ``tempnam'', ``remove'' and ``free'' are prefixed with ``::``, to make sure that it's the names in
global scope that are meant, just in case someone enhances the class with a few more member functions whose name
might clash.
For the sake of syntactical convenience, I have added yet another operator to the ``ptr'' class template:

template <class T> class ptr


{
public:
ptr(T* tp=0) : p(tp) {};
~ptr() { delete p; };
T* operator->(void) const { return p; };
T& operator*(void) const { return *p;};
private:
ptr(const ptr<T>&);
ptr<T>& operator=(const ptr<T>&);
T* p;
};
It's the ``operator->'' that's new, which allows us to write things like ``p->x,'' where p is a ``ptr<X>'', and the type
``X'' contains some member named ``x''. The return type for ``operator->'' must be something that ``operator->'' can
be applied to. The explanation sounds recursive, but it makes sense if you look at the above code.
``ptr<X>::operator->()'' returns an ``X*''. ``X*'' is something you can apply the built in ``operator->'' to (which gives
you access to the elements.)

template <class T>


FileArray<T>::FileArray(size_t elements)
: pfile(new temporaryfile),
stream(pfile->stream()),
array_size(elements),
home(stream.tellg())
{
const size_t elem_size=
FileArrayElementAccess<T>::size;
// put a char just after the end to make
// sure there's enough free disk space.
stream.seekp(home+array_size*elem_size);
char c;
stream.write(&c,1);
// what to do if write fails?
// set put and get pointer to past the end pos
stream.seekg(stream.tellp());
}
That's it! The rest of the array works exactly as before. No need to rewrite anything else.

Code reuse
If you're an experienced C programmer, especially experienced with programming embedded systems where
memory constraints are tough and you also have a good memory, you might get a feeling that something's wrong
here.
What I'm talking about is something I mentioned the first time templates were introduced: ``Templates aren't source
code. The source code is generated by the compiler when needed.'' This means that if we in a program uses
FileArray<int>, FileArray<double>, FileArray<X> and FileArray<Y> (where ``X'' and ``Y'' are some classes,) there
will be code for all four types. Now, have a close look at the member functions and see in what way
``FileArray<int>::FileArray(iostream& fs, size_t elements)'' differs from ``FileArray<char>::FileArray(iostream&
fs, size_t elements)''. Please do compare them.
What did you find? The only difference at all is in the handling of the member ``elem_size'', yet the same code is
generated several times with that as the only difference. This is what is often referred to as the template code bloat
of C++. We don't want code bloat. We want fast, tight, and slick applications.
Since the only thing that differs is the size of the elements, we can move the rest to something that isn't templatised,
and use that common base everywhere. I've already shown how code reuse can be done by creating a separate class
and have a member variable of that type. In this article I want to show an alternative way of reusing code, and that is
through inheritance. Note very carefully that I did not say public inheritance. Public inheritance models ``is-A''
relationships only. We don't want an ``is-A'' relationship here. All we want is to reuse code to reduce code bloat.
This is done through private inheritance. Private inheritance is used far less than it should be. Here's all there is to it.
Create a class with the desired implementation to reuse and inherit privately from it. Nothing more, nothing less. To
a user of your class, it matters not at all if you chose not to reuse code at all, reuse through encapsulation of a
member variable, or reuse through private inheritance. It's not possible to refer to the descendant class through a
pointer to the private base class, private inheritance is an implementation detail only, and not an interface issue.
To the point. What can, and what can not be isolated and put in a private base class? Let's first look at the data. The
``stream'' reference member can definitely be moved to the base, and so can the ``pfile'' member for temporary files.
The ``array_size'' member can safely be there too and also the ``home'' member for marking the beginning of the
array on the stream. By doing that alone we have saved just about nothing at all, but if we add as a data member in
the base class the size (on disk) for the elements, and we can initialise that member through the
``FileArrayElementAccess::size'' traits member, all seeking in the file, including the initial seeking when creating
the file array, can be moved to the base class. Now a lot has been gained. Left will be very little. Let's look at the
new improved implementation:
Now for the declaration of the base class.

class FileArrayBase
{
public:
protected:
FileArrayBase(iostream& io,
size_t elements,
size_t elem_size);
FileArrayBase(iostream& io);
FileArrayBase(size_t elements, size_t elem_size);
iostream& seekp(size_t index) const;
iostream& seekg(size_t index) const;
size_t size() const; // number of elements
size_t element_size() const;
private:
class temporaryfile
{
public:
temporaryfile();
~temporaryfile();
iostream& stream();
private:
char* name;
fstream fs;
};
void initFromFile(const char* p);
ptr<temporaryfile> pfile;
iostream& stream;
size_t array_size;
size_t e_size;
streampos home;
};
The only surprise here should be the nesting of the class ``temporaryfile.'' Yes, it's possible to define a class within a
class. Since the ``temporaryfile'' class is defined in the private section of ``FileArrayBase'', it's inaccessible from
anywhere other than the ``FileArrayBase'' implementation. It's actually possible to nest classes in class templates as
well, but few compilers today support that. When implementing the member functions of the nested class, it looks a
bit ugly, since the surrounding scope must be used.

FileArrayBase::temporaryfile::temporaryfile()
: name(::tempnam(".","array")),
fs(name,ios::in|ios::out|ios::binary)
{
// what if tmpnam fails and name is 0
// what if fs is bad?
}

FileArrayBase::temporaryfile::~temporaryfile()
{
fs.close();
::remove(name);
// What if remove fails?
::free(name);
}

iostream& FileArrayBase::temporaryfile::stream()
{
return fs;
}
The implementation of ``FileArrayBase'' is very similar to the ``FileArray'' earlier. The only difference is that we use
a parameter for the element size, instead of the traits class.

FileArrayBase::FileArrayBase(iostream& io,
size_t elements,
size_t elem_size)
: stream(io),
array_size(elements),
e_size(elem_size)
{
char pattern[sizeof(ArrayBegin)];
stream.read(pattern,sizeof(pattern));
if (stream.eof()) {
stream.clear(); // clear error state
// and initialize.
// begin of array pattern.
stream.write(ArrayBegin,sizeof(ArrayBegin));

// must store size of elements


stream.write((const char*)&elem_size,
sizeof(elem_size));

// and of course the number of elements


stream.write((const char*)&array_size,
sizeof(array_size));

// Now that we've written the maintenance


// stuff, we know what the home position is.
home = stream.tellp();

// Then we must go the the end and write


// the end pattern.

stream.seekp(home+elem_size*array_size);
stream.write(ArrayEnd,sizeof(ArrayEnd));

// set put and get pointer to past the end pos.


stream.seekg(stream.tellp());
return;
}
initFromFile(pattern); // shared with other
// stream constructor

if (array_size != elements) {
// Uh oh. The data read from the stream,
// and the size given in the constructor
// mismatches! What now?

stream.clear(ios::failbit);
}
if (e_size != elem_size) {
stream.clear(ios::failbit);
}
// set put and get pointer to past the end pos.
stream.seekp(stream.tellg());
}
To make life a little bit easier, I've assumed two arrays of char named ``ArrayBegin'' and ``ArrayEnd'', which hold
the patterns to be used for marking the beginning and end of an array on disk.

FileArrayBase::FileArrayBase(iostream& io)
: stream(io)
{
char pattern[sizeof(ArrayBegin)];
stream.read(pattern,sizeof(pattern));
initFromFile(pattern);

// set put and get pointer to past the end pos.


stream.seekp(stream.tellg());
}

FileArrayBase::FileArrayBase(size_t elements,
size_t elem_size)
: pfile(new temporaryfile),
stream(pfile->stream()),
array_size(elements),
e_size(elem_size),
home(stream.tellg())
{
stream.seekp(home+array_size*e_size);
char c;
stream.write(&c,1);
// set put and get pointer to past the end pos.
stream.seekg(stream.tellp());
}

void FileArrayBase::initFromFile(const char* p)


{
// Check if the read pattern is correct
if (strncmp(p,ArrayBegin,sizeof(ArrayBegin))) {
// What to do? It was all wrong!
stream.clear(ios::failbit); // for lack of better,
// set the fail flag.
return;
}
// OK, we have a valid array, now let's see if
// it's of the right kind.
stream.read((char*)&e_size,sizeof(e_size));

// Get the size of the array. Can't do much with


// the size here, though.
stream.read((char*)&array_size,sizeof(array_size));

// Now we're past the header, so we know where the


// data begins and can set the home position.
home = stream.tellg();
stream.seekg(home+e_size*array_size);
// Now positioned immediately after the last
// element.
char epattern[sizeof(ArrayEnd)];
stream.read(epattern,sizeof(epattern));
if (strncmp(epattern,ArrayEnd,sizeof(ArrayEnd)))
{
// Whoops, corrupt file!
stream.clear(ios::failbit);
return;
}
// Seems like we have a valid array!
}

iostream& FileArrayBase::seekg(size_t index) const


{
// what if index is out of bounds?
stream.seekg(home+index*e_size);
// what if seek failed?
return stream;
}

iostream& FileArrayBase::seekp(size_t index) const


{
// What if index is out of bounds?
stream.seekp(home+index*e_size);
// What if seek failed?
return stream;
}
size_t FileArrayBase::size() const
{
return array_size;
}

size_t FileArrayBase::element_size() const


{
return e_size;
}
Apart from the tricky questions, it's all pretty straight forward. The really good news, however, is how easy this
makes the implementation of the class template ``FileArray''.

template <class T>


class FileArray : private FileArrayBase
{
public:
FileArray(iostream& io, size_t size);// create one.
FileArray(iostream& io); // use existing array
FileArray(size_t elements); // create temporary
T operator[](size_t index) const;
FileArrayProxy<T> operator[](size_t index);
size_t size() { return FileArrayBase::size(); };
private:
FileArray(const FileArray<T>&); // illegal
FileArray<T>& operator=(const FileArray<T>&);
// illegal

T readElement(size_t index) const;


void storeElement(size_t index, const T& elem);
friend class FileArrayProxy<T>;
};
Now watch this!

template <class T>


FileArray<T>::FileArray(iostream& io, size_t size)
: FileArrayBase(io,
elements,
FileArrayElementAccess<T>::size)
{
}

template <class T>


FileArray<T>::FileArray(iostream& io)
: FileArrayBase(io)
{
// what if element_size is wrong?
}

template <class T>


FileArray<T>::FileArray(size_t elements)
: FileArrayBase(elements,
FileArrayElementAccess<T>::size)
{
}

template <class T>


T FileArray<T>::operator[](size_t index) const
{
// what if index>= size()?
return readElement(index);
}
template <class T>
FileArrayProxy<T>
FileArray<T>::operator[](size_t index)
{
// what if index>= size()?
return FileArrayProxy<T>(*this, index);
}

template <class T>


T FileArray<T>::readElement(size_t index) const
{
// what if index>= size()?
iostream& s = seekg(index); // parent seekg
return FileArrayElementAccess<T>::readFrom(s);
// what if read failed?
// What if too much data was read?
return t;
}

template <class T>


void FileArray<T>::storeElement(size_t index,
const T& element)
{ // what if index>= size()?
iostream& s = seekp(index); // parent seekp
// what if seek fails?
FileArrayElementAccess<T>::writeTo(element,s);
// what if write failed?
// What if too much data was written?
}
How much easier can it get? This reduced code bloat, and also makes the source code easier to understand, extend
and maintain.

What can go wrong?


Already in the very beginning of this article series, part 1, I introduced exceptions; the C++ error handling
mechanism. Of course exceptions should be used to handle the error situations that can occur in our array class.
When I introduced exceptions, I didn't tell the whole truth about them. There was one thing I didn't tell, because at
that time it wouldn't have made much sense. That one thing is that when exceptions are caught, dynamic binding
works, or to use wording slightly more English-like, we can create exception class hierarchies with public
inheritance, and we can choose what level to catch. Here's a mini example showing the idea:

class A {};
class B : public A {};
class C : public A {};
class B1 : public B{};

void f() (throw A); // may throw any of the above

void x()
{
try {
f();
}
catch (B& b) {
// **1
}
catch (C& c) {
// **2
}
catch (A& a) {
// **3
}
}
At ``**1'' above, objects of class ``B'' and class ``B1'' are caught if thrown from ``f''. In ``**2'' objects of class ``C''
(and descendants of C, if any are declared elsewhere) are caught. At ``**3'' all others from the ``A'' hierarchy are
caught.
This may seem like a curious detail of purely academic worth, but it's extremely useful. We can use abstraction
levels for errors. For example, we can have a root class ``FileArrayException'', from which all other exceptions
regarding the file array inherits. We can see that there are clearly two kinds of errors that can occur in the file array;
abuse and environmental issues outside the control of the programmer. For abuse I mean things like indexing
outside the valid bounds, and with environmental issues I mean faulty or full disks (Since there are several programs
running, a check if there's enough disk space is still taking a chance. Even if there was enough free space when the
check was made, that space may be occupied when the next statement in the program is executed.)
A reasonable start for the exception hierarchy then becomes:

class FileArrayException {};


class FileArrayLogicError
: public FileArrayException {};
class FileArrayRuntimeError
: public FileArray Exception {};
Here ``FileArrayLogicError'' are for clear violations of the not too clearly stated preconditions, and
``FileArrayRuntimeError'' for things that the programmer may not have a chance to do something about. In a
perfectly debugged program, the only exceptions ever thrown from file arrays will be of the
``FileArrayRuntimeError'' kind.
We can divide those further into:

class FileArrayCreateError
: public FileArrayRuntimeError {};
For whenever the creation of the array fails, regardless of why (it's not very easy to find out if it's a faulty disk or
lack of disk space, for example.)

class FileArrayStreamError
: public FileArrayRuntimeError {};
If after creation, something goes wrong with a stream; for example if seeking or reading/writing fails.

class FileArrayDataCorruptionError
: public FileArrayRuntimeError {};
If an array is created from an old existing file, and we note that the header or trailer doesn't match the expected.

class FileArrayBoundsError
: public FileArrayLogicError {};
Addressing outside the legal bounds.

class FileArrayElementSizeError
: public FileArrayLogicError {};
If the read/write members of the element access traits class are faulty and either write too much (thus overwriting the
data for the next element) or reads too much (in which case the last few bytes read will be garbage picked from the
next element.)
It's of course possible to take this even further. I think this is quite enough, though.
Now we have a reasonably fine level of error reporting, yet an application that wishes a coarse level of error
handling can choose to catch the higher levels of the hierarchy only.
As an exercise, I invite you to add the throws to the code. Beware, however; it's not a good idea to add exception
specifications to the member functions making use of the T's (since you cannot know which operations on T's that
may throw, and what they do throw.) You can increase the code size and eligibility gain from the private inheritance
of the implementation in the base by putting quite a lot of the error handling there.

Iterators
An iterator into a file array is something whose behavior is analogous to that of pointers into arrays. We want to be
able to create an iterator from the array (in which case the iterator refers to the first element of the array.) We want
to access that element by dereferencing the iterator (unary operator *,) and we want iterator arithmetic with integers.
An easy way of getting there is to let an iterator contain a pointer to a file array, and an index. Whenever the iterator
is dereferenced, we return (*array)[index]. That way we even have error handling for iterator arithmetic that lead us
outside the valid range for the array given for free from the array itself. The iterator arithmetics becomes simple too,
since it's just ordinary arithmetics on the index type. The implementation thus seems easy; all that's needed is to
define the operations needed for the iterators, and the actions we want. Here's my idea:
• creation from array yields iterator referring to first element
• copy construction and assignment are of course well behaved.
• moving forwards and backwards with operator++ and operator--.
• addition of array and ``long int'' value ``n'' yields iterator referring to n:th element of array.
• iterator+=n (where n is of type long int) adds n to the value of the index in the iterator. This addition is
never an error; it's dereferencing the iterator that's an error if the index is out of range. Operator -= is
analogous.
• iterator+n yields a new iterator referring to the iterator.index+n:th element of the array, and analogous for
operator-.
• iterator1-iterator2 yields a long int which is the difference between the indices of the iterators. If iterator1
and iterator2 refer to different arrays, it's an error and we throw an exception.
• iterator1==iterator2 returns non-zero if the arrays and indices of iterator1 and iterator2 are equal.
• iterator1!=iterator2 returns !(iterator1==iterator2)
• *iterator returns whatever (*array)[index] returns, i.e a
• leArrayProxy. * iterator[n] returns (*array)[index+n].
• iterator1<iterator2 returns true if the iterators refer to the same array and iterator1.index < iterator2.index. If
the iterators refer to different arrays, it's an error and we throw an exception. Likewise for operator>.
• iterator1>=iterator2 returns !(iterator1<iterator2). Likewise for operator<=.
I think the above is an exhaustive list. Neither of the above is difficult. It's just a lot of code to write, and thus a good
chance of making errors. With a little thought, however, quite a lot of code can be reused over and over, thus
reducing the amount to write and also the risk for errors. As an example, a rule of thumb when writing a class for
which an object ``o'' and some other value ``v'' the operations ``o+=v'', ``o+v'' and ``v+o'' are well defined and
behaves like they do for the built in types (which they really ought to, unless you want to give the class users some
rather unhealthy surprises) is to define ``operator+='' as a member of the class, and two versions of operator+ that
are implemented with ``operator+=''. Here's how it's done in the iterator example:

template <class T>


class FileArrayIterator
{
public:
FileArrayIterator(FileArray<T>& f);
FileArrayIterator<T>& operator+=(long n);
FileArrayProxy<T> operator*();
FileArrayProxy<T> operator[](long n);
...
private:
FileArray<T>* array;
unsigned long index;
};

template <class T> FileArrayIterator<T>


operator+(const FileArrayIterator<T>& i, long n);

template <class T> FileArrayIterator<T>


operator+(long n, const FileArrayIterator<T>& i);

template <class T>


FileArrayIterator<T>::FileArrayIterator(
const FileArray<T>& a
)
: array(&a),
index(0)
{
}

template <class T>


FileArrayIterator<T>::FileArrayIterator(
const FileArrayIterator<T>& i
)
: array(i.array),
index(i.index)
{
}

template <class T>


FileArrayIterator<T>&
FileArrayIterator<T>::operator+=(long n)
{
index+=n;
return *this;
}

template <class T> FileArrayIterator<T>


operator+(const FileArrayIterator<T>& i, long n)
{
FileArrayIterator<T> it(i);
return it+=n;
}

template <class T> FileArrayIterator<T>


operator+(long n, const FileArrayIterator<T>& i)
{
FileArrayIterator<T> it(i);
return it+=n;
}

template <class T>


FileArrayProxy<T> FileArrayIterator<T>::operator*()
{
return (*array)[index];
}

template <class T>


FileArrayProxy<T>
FileArrayIterator<T>::operator[](long n)
{
return (*array)[index+n];
}
Surely, the code for the two versions of ``operator+'' must be written, but since its behaviour is defined in terms of
``operator+='' it means that if we have an error, there's only one place to correct it.
There's no need to display all the code here in the article, you can study it in the sources. The above shows how it all
works, though, and as you can see, it's fairly simple.

Recap
This month the news in short was:
• You can increase flexibility for your templates without sacrificing ease of use or safety by using traits
classes.
• Enumerations in classes can be used to have class-scope constants of integral type.
• Modern compilers do not need the above hack. Defining a class-scope static constant of an integral type in
the class declaration is cleaner and more type safe.
• Standard C++ and even C, does not have any support for the notion of temporary files. Fortunately there are
commonly supported extensions to the languages that do.
• Private inheritance can be used for code reuse.
• Private inheritance is very different from public inheritance. Public inheritance models ``is-A''
relationships, while private inheritance models ``is-implemented-in-terms-of'' relationships.
• A user of a class that has privately inherited from something else cannot take advantage of this fact. To a
user the private inheritance doesn't make any difference.
• Private inheritance is in real-life used far less than it should be. In many situations where public inheritance
is used, private inheritance should've been used.
• Exception catching is polymorphic (i.e. dynamic binding works when catching.)
• The polymorphism of exception catching allows us to create an arbitrarily fine-grained error reporting
mechanism while still allowing users who want a coarse error reporting mechanism to use one (they'll just
catch classes near the root of the exception class inheritance tree.)
• Always implement binary operator+, operator-, operator* and operator/ as functions outside the classes, and
always implement them in terms of the operator+=, operator-=, operator*= and operator/= members of the
classes.

Exercises
• Alter the file array such that it's possible to instantiate two (or more) kinds of FileArray<X> in the same
program, where the alternatives store the data in different formats. (hint, the alternatives will all need
different traits class specialisations.)
• What's the difference between using private inheritance of a base class, and using a member variable of that
same class, for reusing code?
• In which situations is it crucial which alternative you choose?

Coming up
Next month we'll have a look at smart pointers. I'm beginning to dry up on topics now, however, so please write and
give me suggestions for future topics to cover.

Part Part Part Part Part Part Part Part Part Part1 Part1 Part1 Part1
1 2 3 4 5 6 7 8 9 0 1 2 3
[Note: the source code for this month is here. Ed.]
In the past two articles, we've seen how a simple smart pointer, called simply ``ptr<T>'' was used to make memory
handling a little bit easier. That is the core purpose of all smart pointers. You can find a few things in common with
them all. They're templates, they relieve you of the burden of remembering to deallocate the memory, their syntax
resembles that of pointers, they aren't pointers, and they're dangerous if you forget that you're dealing with smart
pointers.
While ``ptr<T>'' served its purpose, it's a bit too simplistic to be generally useful. For example there was no way to
rebind an object to another pointer, or to tell it not to delete the memory (that too can be useful at times, as we will
see later in this article.)
This article is devoted to the only smart pointer provided by the standard C++ library; the class template
``auto_ptr<T>''.

The problem to solve


I do not know what the core issues where when the ``auto_ptr<T>'' was designed, but I know what problems the
implementation provided does solve.
• exception safety
• safe memory area ownership transfer
• no confusion with normal pointers
• controlled and visible rebinding and release of ownership
• works with dynamic types
• pointer-like syntax for pointer-like behaviour
Let us have a look at each of these in some detail and compare with the previous ``ptr<T>''.

Exception safety
In this respect ``auto_ptr<T>'' and ``ptr<T>'' are equal. They both delete whatever they point to in their
destructor. The only thing that ``auto_ptr<T>'' has to offer over ``ptr<T>'', with respect to exception safety, is
that we can tell an ``auto_ptr<T>'' object that it no longer owns a memory area. This can be used for holding
onto something we want to return in normal cases, but deallocate in exceptional situations. Here is a code fragment
showing such a situation:

void f(); // may throw something


int* ptr()
{
// returns a newly allocated value on success,
// or the 0 pointer on failure.
try {
auto_ptr<int> p(new int(1));
f();
return p.release();
} catch (...) {
return 0;
}
}
In the code above, an exception thrown from ``f'' results in the destruction of the ``auto_ptr<int>'' object ``p''
before the call of the ``release'' member function, which means that the object pointed to will be deleted.
If, however, ``f'' does not throw any exception, ``p.release()'' is called, and the value returned from there is
passed to the caller. The member function ``release'' releases ownership of the memory area from the
``auto_ptr<int>'' object. The value returned is the pointer to the memory area. Since the object no longer owns
the memory area, it will not be deallocated.

Safe memory area ownership transfer


This safety is achieved by cheating in the ``assignment'' operator and ``copy'' constructor. The reason I've quoted the
names assignment and copy, is that the cheat is so bad that it's not really an assignment and definitely not a copy.
Rather, both are ownership transfer operations. What happens is that they both modify the right hand side, by
relieving it of ownership while accepting ownership itself. Below are some examples of this:

// simple transfer
auto_ptr<int> p1(new int(1));
// p1 owns the memory area.
auto_ptr<int> p2;
// p2 doesn't own anything.
p2 = p1;
// now p2 owns the memory area, p1 doesn't.
// p1 has become the 0 "pointer"
auto_ptr<int> p3(p2);
// Now it is p3 that owns the memory area, not
// p1 or p2.
I think the above example speaks for itself. An important issue here for those of you who have used early versions of
the ``auto_ptr<T>'' is that older versions did not become 0 ``pointers'' when not owning the memory area, but that is
the behaviour set in the final draft of the C++ standard. Of course, the above program snippet is too simplistic to be
useful. The properties of the ``auto_ptr<T>'' are more useful when working with functions, where it works as
both documentation and implementation of ownership transfer. What do you think about this?

auto_ptr<int> creation();
void termination(auto_ptr<int> rip);
void f()
{
auto_ptr<int> pi=creation();
// It's now clear that we are responsible for
// deletion of the memory area allocated. Even
// if we chose to release ownership from "pi",
// we must take care of deallocation somehow.

... // use pi for something

termination(pi);

// since we're sending it off as an auto_ptr<T>,


// deletion is not our headache anymore, and since
// the function "termination" wants an auto_ptr<T>
// it wants the responsibility.
}
One of the headaches of using dynamically allocated memory is knowing who is responsible for deallocating the
memory at any given moment in a program's lifetime. The ``auto_ptr<T>'' makes that rather easy, as can be seen
above. Any function that returns an ``auto_ptr<T>'' leaves it to the caller to take care of the deallocation, and any
function that accepts an ``auto_ptr<T>'' requires ownership to work. If something goes wrong between calling
``creation'' and ``termination'', such that ``termination'' ought not be called, we must take care of the
deallocation, but since we have it in an ``auto_ptr<T>'' that is automatically done for us if we return or throw an
exception.
This functionality is an advantage that ``auto_ptr<T>'' offer over ``ptr<T>'', since the latter doesn't have any
way of transferring ownership.

No confusion with normal pointers


Since the auto pointers have the behaviour outlined above, it is extremely important that they cannot accidentally be
confused with normal pointers. This is done by explicitly prohibiting all implicit conversions between pointer types
and ``auto_ptr<T>'' types. The erroneous code below shows how:

auto_ptr<int> creator();
void termination(auto_ptr<int>);
void f()
{
int* p = creator();
// illegal. An auto_ptr<T> cannot be implicitly
// converted to a pointer.

auto_ptr<T> ap=p;
// illegal. A pointer cannot be implicitly
// converted to an auto_ptr<T>. When creating a
// new auto_ptr<T> object, use the constructor
// syntax auto_ptr<T> ap(p);

ap=p;
// also illegal. If you want to rebind an
// auto_ptr<T> object to point to something else,
// use the "reset" member function; ap.reset(p).

termination(p);
// also illegal. The auto_ptr<T> required by the
// termination function cannot be implicitly
// created from the pointer.
}
It is indeed fortunate that the first and last error above are illegal. Imagine the maintenance headaches you could get
otherwise. What would the first mean? Would the implicit conversion from ``auto_ptr<T>'' to a raw pointer
transfer ownership or not? All implementations I have seen where such implicit conversions are allowed do not
transfer the ownership, which in the situation above means that the memory would be deallocated when the
``auto_ptr<T>'' object returned is destroyed (which it would be immediately after the conversion.) The last is
as bad. What about this situation?

int i;
termination(&i);
Ouch! The function would attempt to delete the local variable. For both the result will be something that in
standardese is called ``undefined behaviour'', but which in normal English best translates to ``a crash now, a crash
later, or generally funny behaviour (possibly followed by a crash later.)'' Well, since it is illegal, we do not have to
worry about it.
The second error ``auto_ptr<int> ap=p;'' is perhaps a bit unfortunate since the intended behaviour is clear.
That it is illegal comes as a natural consequence of banning the third situation ``ap=p'' which is not clear. ``ap''
might be declared somewhere far far away, so that in the code near the assignment it is not obvious if it is an
``auto_ptr<T>'' or a normal pointer.
In this respect ``auto_ptr<T>'' is better than ``ptr<T>'', since ``ptr<T>'' does allow implicit construction,
allowing the last error.

Controlled and visible rebinding and release of ownership


If we want to rebind an ``auto_ptr<T>'' object to another memory area, it is important that the memory area
currently owned by the object (if any) is deallocated. The member function ``reset'' takes care of that. Calling
``ap.reset(p)'' will deallocate whatever ``ap'' owns (if anything) and make it own whatever ``p'' points to.
If we want a normal pointer from an ``auto_ptr<T>'' object, we can get it in two ways, depending on the desired
effect. The member function ``release'' gives us a normal pointer to the memory area owned by the
``auto_ptr<T>'' object, and also gives us the ownership, so that we will be responsible for the deallocation. If we
do not want that responsibility, but temporarily need a normal pointer to the memory area, we use the ``get''
member function. Here is an example showing the differences:

void func(const int*); // may throw


int* f(void)
{
auto_ptr<int> p(new int(1));
func(p.get()); // call func with a normal pointer
return p.release(); // return the pointer
}
Above we see that the function ``func'' requires a normal pointer, but it does not assume ownership, so we use the
``get'' member to temporarily get the pointer and pass it to ``func''. This function ``f'' then returns the raw pointer
if ``func'' does its job, but if it fails with an exception, the ``auto_ptr<int>'' object ``p'' will deallocate the
memory in its destructor.
Since ``ptr<T>'' was specifically designed to disallow transfer of ownership, this functionality is added-value for
``auto_ptr<T>''.

Works with dynamic types


Just as a normal pointer to a base class can point to an object of a publicly derived class, an ``auto_ptr<T>'' can
too. This is not particularly strange:

class A {};
class B : public A{};
auto_ptr<A> pa(new B());
auto_ptr<B> pb(new B());
pa=pb;
auto_ptr<A> pa2(pb);
The reverse is (of course) not allowed. For ``ptr<T>'' this is not a problem, since the functionality is only required
if ownership transfer is allowed.

Pointer-like syntax for pointer-like behaviour


For the small subset of a pointer's functionality that is implemented in the ``auto_ptr<T>'' class template, the
syntax is exactly the same. We get access to the element pointed to with ``operator*'' and ``operator->''. This
is the only functionality of a pointer that is implemented. Here it is a tie between ``auto_ptr<T>'' and
``ptr<T>'', since the functionality is exactly the same and so is the syntax.

Implementation
The definition of ``auto_ptr<T>'' looks as follows:

template <class T>


class auto_ptr
{
public:
explicit auto_ptr(T* t = 0) throw ();
auto_ptr(auto_ptr<T>& t) throw();
template <class Y> auto_ptr(auto_ptr<Y>& t) throw();
~auto_ptr() throw ();
auto_ptr<T>& operator=(auto_ptr<T>& t) throw ();
template <class Y>
auto_ptr<T>& operator=(auto_ptr<Y>& t) throw ();
T& operator*() const throw ();
T* operator->() const throw ();
T* release() throw ();
void reset(T* t = 0) throw ();
T* get(void) const throw ();
private:
T* p;
};
Three new details can be seen above. The keyword ``explicit'' in front of the constructor, and ``template
<class Y>'' inside the class definition. Both of these are relatively recent additions to the C++ language and far
from all compilers support them. Third, and most important (please take note of this,) is that the ``copy'' constructor
and ``assignment'' operator do take a non-const reference to their right hand side, so that it can be modified.
``explicit'' is what disallows implicit construction of objects, for example in function calls (see the error
example above, when attempting to call a function requiring an ``auto_ptr<T>'' parameter with a normal
pointer.) This keyword is, strictly speaking, not needed. There is a fake around it, which you will see when we get to
the implementation details. The member templates, as the ``template <class Y>'' used inside the class
definition is called, is a way of creating new member functions at need. This is what makes it possible to say
``auto_ptr<A> pa; auto_ptr<B> pb; pa=pb''. With this mini-example, and the code above, we can see
that a member function

auto_ptr<A>&
auto_ptr<A>::operator=(auto_ptr<B>&) throw()
will be generated. If class ``B'' is publicly derived from class ``A'', the generated code will compile just fine,
otherwise we will get an error message from the compiler. This feature can, to the best of my knowledge, not be
worked around. It is an essential addition to the C++ language. Unfortunately even fewer compilers support this than
support the ``explicit'' keyword.

The code
Let us do the member functions one by one, beginning with the constructor. The only thing it needs to do is to
initialize the ``auto_ptr<T>'' object such that it owns the memory area, and if it points to anything at all, it owns
it (by definition.)

template <class T>


inline auto_ptr<T>::auto_ptr(T* ptr) throw()
: p(ptr)
{
}
The ``inline'' keyword is new for this course, although it has been part of C++ for a very long time. Marking a
function ``inline'' is a way of hinting to the compiler that you think this function is so simple that it can insert the
function code directly where needed, instead of making a function call. This is just a hint; a compiler is free to
ignore it, and likewise a good compiler may inline even functions not marked as inline (provided you cannot see any
difference in the behaviour of the program.) Few compilers are smart enough to inline automatically, however, so
there's a place for the ``inline'' keyword, and it will be used for all member functions of the ``auto_ptr<T>''.
This constructor is marked ``explicit'' in the class definition. I mentioned above that the ``explicit'' keyword
is not, strictly speaking, necessary. Here is the promised work-around:

template <class T>


class explicit
{
public:
explicit(T t) : value(t) {};
operator T() const { return value; };
private:
T value;
};

template <class T>


inline auto_ptr<T>::auto_ptr(explicit<T*> ptr) throw()
: p(ptr)
{
}
The way this works is as follows: By default, implicit conversions are allowed, but only one user defined implicit
conversion may take place. It is an error if two or more implicit conversions are required to get the desired effect.
Constructing an object is a user defined conversion, and executing a conversion operator is too. Look at this
example usage:

void termination(auto_ptr<int> pi);


void func()
{
auto_ptr<int> pi(new int(1)); //**1 legal
termination(new int(2)); //** 2 error
}
The code at //**1 is not in error, because we say that we want an object of type ``auto_ptr<int*>''. Since
we've been so stern about this, we will be obeyed. It may seem like there are two implicit conversions taking place
here, one for creating the ``explicit<T>'' object, and one for getting the value out of it, but that is not quite true.
Our ``auto_ptr<int>'' accepts as its parameter an ``explicit<int*>'' which is implicitly created from the
pointer value. Then, it is a detail of the innards of the ``auto_ptr<T>'' constructor how it is used, in this case to
get the value from it.
The code at //**2 however, is in error, because the call to ``termination'' requires two user defined
conversions. One from ``int*'' to ``explicit<int*>'', and one from ``explicit<int*>'' to
``auto_ptr<int>''.
Please see the provided source code for how to allow both versions to coexist for different compilers in the same
source file.

template <class T>


inline auto_ptr<T>::auto_ptr(auto_ptr<T>& t) throw()
: p(t.release())
{
}
There is not much strange going on here, except that the parameter is a non-const reference. As mentioned far
above, the member ``release'' relieves the object of ownership and returns the pointer. Thus this constructor
makes ``p'' point to what ``t'' did point to, and alters ``t'' so that it becomes the 0 ``pointer''.

template <class T> template <class Y>


inline auto_ptr<T>::auto_ptr(auto_ptr<Y>& t) throw()
: p(t.release())
{
}
The code for this constructor is, of course, the same as for the previous one. Note that both are necessary. I made a
mistake with the ``auto_ptr<T>'' implementation available in the adapted SGI STL, that I thought the latter
would imply the former. It doesn't, however, even though it may seem so.
Note, by the way, the syntax for a member template, with the two subsequent ``template <...>''
Of course, users of compilers that do not implement member templates will get compilation errors on this member
function. Please see the source code for how to work around the compilation error (the work around is simply not to
have this member function, which means that the resulting ``auto_ptr'' will be limited in functionality.)

template <class T>


inline auto_ptr<T>::~auto_ptr() throw ()
{
delete p;
}
If the object owns anything, it will be deleted by the destructor. Note that deleting the 0 pointer is legal, and does
nothing at all. If the object does not own anything, ``p'' will be the 0 pointer.

template <class T>


inline auto_ptr<T>&
auto_ptr<T>::operator=(auto_ptr<T>& t) throw ()
{
reset(t.release());
return *this;
}

template <class T> template <class Y>


inline auto_ptr<T>&
auto_ptr<T>::operator=(auto_ptr<Y>& t) throw ()
{
reset(t.release());
return *this;
}
This is pretty much the same story as the ``copy'' constructor. Since we are not creating a new object, however, we
cannot just assign to ``p'' (it may point to something, in which case it must be deallocated.) The member function
``reset'' does exactly what we want; delete whatever ``p'' points to, and give it a new value.

template <class T>


inline T& auto_ptr<T>::operator*() const throw ()
{
return *p;
}

template <class T>


inline T* auto_ptr<T>::operator->() const throw ()
{
return p;
}
These are not identical with the version of ``ptr<T>'' from the previous issue of the course. One word on the way,
though. ``operator->'' can, of course, only be used if ``T'' is a struct or class type. On some older compilers, it's
even illegal to instantiate ``auto_ptr<T>'' if ``T'' is not a struct or class type. In most cases this is a minor
limitation; after all, it is normally structs and classes you handle this way, and not built-in types.

template <class T>


inline T* auto_ptr<T>::release() throw ()
{
T* tp=p;
p=0;
return tp;
}
Not much to say, is there? The object is relieved of ownership by making ``p'' the 0 pointer, and the value
previously held by ``p'' is returned; just as mentioned in the introduction of the class.

template <class T>


inline void auto_ptr<T>::reset(T* t) throw ()
{
if (t != p) {
delete p;
p=t;
}
}
Deletes what it points to and sets ``p'' to the given value. Nothing strange, except the safety guard against resetting
to the value already held. If we didn't have this guard, resetting to the current value would deallocate the memory
and keep the ownership of it, for later deletion again! It seems like a better way is to just do nothing if the situation
ever arises.

template <class T>


inline T* auto_ptr<T>::get(void) const throw ()
{
return p;
}
Not much to say about this one.

Efficiency
The question of efficiency pops up now and then. How much does it cost, performance and memory-wise to use the
``auto_ptr<T>'' instead of ``ptr<T>'' from last month?
If you use ``auto_ptr<T>'' instead of ``ptr<T>'', and use only the functionality that ``ptr<T>'' offers, the price
is nothing at all. The constructor, destructor, ``operator*'' and ``operator->'' holds exactly the same code for
both templates. You pay for what you use only.
Compared to raw pointers and doing your own deletion? I do not know. It will depend a lot on how clever your
compiler is with inlining. Most probably close to none at all. If you have a measurable speed difference in a real-
world application, I would say the difference is that with ``auto_ptr<T>'' you do many more deletions (i.e. you
have mended memory leaks you were not aware of having.)
Recap
The news this month were:
• The standard class template ``auto_ptr<T>'' handles memory deallocation and ownership transfer.
• Automatic memory deallocation and ownership transfer reduces the risk for memory leaks, especially when
exceptions occur.
• Implicit conversions between raw pointers and smart pointers is bad (even if it may seem tempting at first.)
• The ``explicit'' keyword disallows implicit construction of objects.
• The ``explicit'' keyword can be faked.
• Member templates can be used to create member functions at compile time, just like function templates can
be used to create functions at compile time.
• ``inline'' hints to a compiler that you think a function is so small that it is better to directly insert the
function code where required instead of making a function call.

Exercises
• Why is it a bad idea to have arrays (or other collections) of ``auto_ptr<T>''?
• Can smart pointers be dangerous? When? ``auto_ptr<T>'' too?
• What is a better name for this function template?

template <class T>


void funcname(auto_ptr<T>)
{
}
• What happens if ~T throws an exception?

Coming up
If I missed something, or you want something clarified further or disagree with me, please drop me a line and I'll
address your ideas in future articles.
Next month we'll have a look at a smarter pointer; a reference counted one. I'm beginning to dry up on topics now,
however, so please write and give me suggestions for future topics to cover.

Part Part Part Part Part Part Part Part Part Part1 Part1 Part1 Part1
1 2 3 4 5 6 7 8 9 0 1 2 3

Introduction
Last month's ``auto_ptr<T>'' class template, documents and implements ownership transfer of dynamically
allocated memory. Often, however, we do not want to be bothered with ownership. We want several places of the
code to be able to access the memory, but we also want to be sure that the memory is deallocated when no longer
needed. The general solution to this is called automatic garbage collection (something you can read several theses
on, and also buy a few commercially available libraries for.) The less general solution is reference counting; no
owner, but last one out locks the door. The idea is that a counter is attached to every object allocated. When
allocated it is set to 0. When the first smart pointer attaches to it, the count is incremented to 1. Every smart pointer
attaching to the resource, increments the reference count; and every smart pointer detaching from a resource (the
smart pointer destroyed, or assigned another value) the resource's counter is decremented. If the counter reaches
zero, no one is referring to it anymore, so the resource must be deallocated. The weakness of this compared to
automatic garbage collection is that it does not work with circular data structures (the count never goes below 1.)

The problems to solve


Many of the problems with a reference counting pointer are the same as for the auto pointer. The list is actually a bit
shorter, since there's no need to worry about ownership.
• exception safety
• no confusion with normal pointers
• controlled and visible rebinding and access
• works with polymorphic types
• pointer-like syntax for pointer-like behaviour
• automatic deletion when no longer referring to the object
This might also be the place to mention a problem not to solve; that of how to stop reference counting a resource.
Adding this functionality is not difficult, but it quickly leads to user code that is extremely hard to maintain. This is
exactly what we want to avoid, so it is better not to have the functionality.
Here is how it is supposed to work when we are done:
counting_ptr<int> P1(new int(value));

After creating a counting pointer ``P1'', the reference count for the value pointed to is set to one.
counting_ptr<int> P2(P1);

When a second counting pointer ``P2'' is created from ``P1'', the object pointed to is not duplicated, but the
reference count is incremented.
counting_ptr<int> P3(P2);

When three counting pointers refer to the same object, the value of the counter is three.
P1.manage(new int(other));
As one of the pointers referring to the first object created is reinitialized to another object, the old reference count is
decremented (there are only two references to it now) and the new one is assigned a reference count of 1.
P2=P1;

When yet one of the pointers move attention from the old object to the new one, the counter for the old one is yet
again decremented, and for the new one it is incremented.
P3=P2;

Now that the last counting pointer referring to the old object moves its attention away from it, the old objects
reference count goes to zero, and the object is deallocated. Now instead the new object has a reference count of 3,
since there are three reference counting pointers referring to it.
Interface outline
The interface of the reference counting smart pointer will, for obvious reasons, share much with the auto pointer.
The differences lie in accessing the raw pointer and giving the pointer a new value. While these aspects could use
the same interface as does the auto pointer, giving the reference counting pointer an identical interface, this would
be very unfortunate since their semantics differ dramatically. Here is a suggested interface.
template <class T>
class counting_ptr
{
public:
explicit counting_ptr(T* t = 0);
counting_ptr(const counting_ptr<T>& t) throw();
template <class Y>
counting_ptr(const counting_ptr<Y>& ty) throw();
~counting_ptr() throw ();
counting_ptr<T>&
operator=(const counting_ptr<T>& t) throw ();
template <class Y>
counting_ptr<T>&
operator=(const counting_ptr<Y>& ty) throw();
T& operator*(void) const throw ();
T* operator->(void) const throw ();
T* peek(void) const throw();
void manage(T* t);
};
Compared to the auto pointer, the only differences are that some member functions do not have an empty exception
specification, and there is no member function corresponding to ``auto_ptr<T>::release()'' (which stops
the managing of the pointer.) The member function ``get'' is here named ``peek''. I think this name better
describes what is happening. To me the word ``get'' associates with a transfer, and there is no transfer occurring.
All we do is to peek inside and see what the internal raw pointer value is. The member function ``reset'' is here
named ``manage'', and the reason is a big difference in semantics.

Where to store the reference count


Before we can dive into implementation, we must figure out where to store the reference count. It is obvious that the
counter belongs to the object referred to, so it cannot reside in the smart pointer object. A solution that easily springs
to mind is to use a struct with a counter, and the type referred to, like this:
template <class T>
class counting_pointer {
public:
private:
struct representation {
unsigned counter;
T value;
};
representation* ptr;
};
With this construct, we have the object and counter together. Unfortunately there are two severe drawbacks. We
cannot use it for dynamic binding, since the ``value'' component is indeed a value and dynamic binding only
works through pointers and references. It also becomes very difficult to write the constructor and ``manage''
member function.
The work around is simple; use a ``T*'' instead. All we need to work this way is to make sure to allocate this
representation struct on heap in the constructor and ``manage'' member functions (and of course to deallocate the
struct when we're done with it.)
There is a performance disadvantage with this, however. Whenever accessing the object referred to, we must follow
two pointers, the pointer to the representation and the pointer to the object from the representation.
The best solution I have seen is to decouple the representation from the object and instead allocate an ``unsigned''
and in every counting pointer object keep both a pointer to the counter and to the object referred to. This gives the
following data section of our counting pointer class template:
template <class T>
class counting_pointer {
public:
private:
T* ptr;
unsigned* pcount;
};

Accessibility
The solution outlined above is so good it almost works. For compilers that do not support member templates, such
that the assignment and construction from a counting pointer of another type are impossible, it is all we need.
However, if we want the ability to assign a ``counting_ptr<T>'' object from a value of type
``counting_ptr<Y>'' if a ``T*'' can be assigned from a ``Y*'', we must think of something. The problem is that
``counting_ptr<T>'' and ``counting_ptr<Y>'' are two distinct types, so both the member variables are
private and thus inaccessible. The value of the raw pointer member can be accessed through the public ``peek''
member function, but we need a solution for accessing the counter without making it publicly available.
This kind of problem is exactly what ``friend'' declarations are for, but there is a two-fold problem with that. To
begin with, extremely few compilers support template friends; a rather new addition to the language. Second,
member templates open up holes in the type system you can only dream of. For the curious, please read Scott
Meyer's paper on the topic.
One step on the way towards a solution is to see that the management of the counter is independent of the type T, so
we can implement the counter managing code in a separate class. A reference counting class may look like:
class counting_base
{
public:
counting_base(unsigned count = 0);
counting_base(const counting_base& cb) throw();
counting_base&
operator=(const counting_base& cb) throw ();
~counting_base(void) throw();
int release() throw();
int reinit(unsigned count=1);
private:
unsigned* pcount;
};
The idea here is that the this class handles every aspect of the reference counter. We just need to tell it how to
behave, and it reports the results to us.
The default constructor allows us to choose whether we want a reference counter or not. If our reference counting
pointer is initialized with the 0 pointer, there is no need to waste time and memory by allocating a reference counter
for it.
The member functions ``release'' and ``reinit'' return 1 if the old counter is discarded (and hence, we should
delete the object we refer to) or 0 if it was just decremented.

Base implementation
It is fairly easy to implement, and makes life easier later on, even when member templates are not available.
inline counting_base::counting_base(unsigned count)
: pcount(count ? new unsigned(count) : 0)
{
if (count && !pcount) throw bad_alloc();
}
Initialize a counter with the value of the parameter. A count of 0 is represented by a 0 pointer. If you have a modern
compiler, the function body throwing the exception will not be necessary; operator new will throw ``bad_alloc''
in out-of-memory conditions. For older compilers, however, you need to define the ``bad_alloc'' class.
inline counting_base::counting_base(
const counting_base& cb
) throw ()
: pcount(cb.pcount)
{
if (pcount) ++(*pcount);
}
Copying a reference counting object means adding one to the reference counter (since there is now one more object
referring to the counter.) When we have 0 pointers, there is nothing to update. Note that the copy constructor never
involves any allocation or deallocation of dynamic memory. In fact, there is nothing in the copy constructor that can
throw exceptions.
inline counting_base::~counting_base() throw()
{
release();
}
Destroying a reference counting object means decrementing the reference counter and deallocating it if the count
goes to zero (last one out locks the door.) Since this code is needed in the assignment operator, as well as in the
public interface for use by the reference counted smart pointer class template, we implement that work in the
``release'' member function.
inline counting_base&
counting_base::operator=(
const counting_base& cb
) throw()
{
if (pcount != cb.pcount) {
release();
pcount=cb.pcount;
if (pcount) ++(*pcount);
}
return *this;
}
Assignment of reference counting objects means decrementing the reference count for the left hand side object, and
incrementing it for the right hand side object; since there will be one less object referring to the counter from the left
hand side object, and one more referring to the counter from the right hand side object.
inline int counting_base::release() throw ()
{
if (pcount && --(*pcount) == 0) {
delete pcount;
pcount = 0;
return 1;
}
pcount=0;
return 0;
}
If the reference count goes to zero the counter is deallocated. A return value of 1 means deallocation took place
(hinting to the user of this class that it should deallocate whatever object it refers to, since it is the last one referring
to it.) In both cases the pointer to the counter is set to 0 as a precaution. It may be that ``release'' is called just
prior to destruction, and the destructor calls ``release'' to deallocate memory. If the pointer to the counter is not
set to zero it means either referring to just deleted memory, or decrementing the reference count twice.
inline int counting_base::reinit(unsigned count)
{
if (pcount && --(*pcount) == 0) {
*pcount = count;
return 1;
}
pcount = count ? new unsigned(count) : 0;
if (count && !pcount) throw bad_alloc();
return 0;
}
Strictly speaking, ``reinit'' is not needed. Its purpose is to release from the current counter and initialize a new
one with a defined value. It is an optimization of memory handling, however, in that if this object was the last
reference the counter is reinitialized instead of deallocated and then allocated again. If it was not the last object
referring to the counter, a new counter must of course be allocated.
As an exercise, prove to yourself that this reference counting base class does not have any memory handling errors
(i.e. it always deallocates what it allocates, never deallocates the same area twice, never accesses uninitialized or just
deallocated memory, and never dereferences the 0 pointer.)

Accessibility again
As nice and convenient the above helper class is, it really does not solve the accessibility problem. It does make the
implementation a bit easier, though.
The problem remains. class ``counting_ptr<T>'' and ``counting_ptr<Y>'' are different classes and because
of this are not allowed to see each others private sections. The easy way out is to use public inheritance, and say that
every counting pointer is-a counting base. That is a solution that is simple, sweet and dead wrong. There is no is-a
relationship here, but an is-implemented-in-terms-of relationship. Such relationships are implemented through
private member data or private inheritance - almost. This is bordering on abuse, but it works fine. Instead of having
the member functions of the ``counting_base'' class public, they can be declared protected. As such they do not
become part of the public interface, and the is-a relationship is mostly imaginary.

Implementation of a reference counting pointer


Finally we can get to work and write the reference counting pointer, and since the helper class does most of the dirty
work, the implementation is not too convoluted.
template <class T>
inline counting_ptr<T>::counting_ptr(T* t)
: counting_base(t ? 1 : 0),
pt(t)
{
}
Initialize the counter to 1 if we have a pointer value, and 0 otherwise.
template <class T>
inline counting_ptr<T>::counting_ptr(
const counting_ptr<T>& t
) throw()
: counting_base(t),
pt(t.pt)
{
}

template <class T> template <class Y>


inline counting_ptr<T>::counting_ptr(
const counting_ptr<Y>& ty
) throw()
: counting_base(ty),
pt(ty.peek())
{
}
Note how the latter makes use of the knowledge that a ``counting_ptr<Y>'' is-a ``counting_base''.
inline counting_ptr<T>::~counting_ptr() throw()
{
if (release()) delete pt;
}
The destructor is important to understand. If you review the functionality of the ``release'' member function of
``counting_base'', you see that it deallocates the counter if, and only if, the count reaches 0 and then returns 1,
otherwise it returns 0. This means that in the destructor we will deallocate whatever ``pt'' points to if, and only if
the reference count for it reaches zero and is deallocated.
template <class T>
inline counting_ptr<T>&
counting_ptr<T>::operator=(
const counting_ptr<T>& t
) throw()
{
if (pt != t.pt) {
if (release()) delete pt;
counting_base::operator=(t);
pt=t.pt;
}
return *this;
}

template <class T> template <class Y>


inline counting_ptr<T>&
counting_ptr<T>::operator=(
const counting_ptr<Y>& ty
) throw()
{
if (pt != ty.peek()) {
if (release()) delete pt;
counting_base::operator=(ty);
pt=ty.peek();
}
return *this;
}
Please spend some time convincing yourself that the above works. What happens is that if the left hand side and
right hand side counting pointers already refer to the same object, nothing happens. If they refer to different objects,
on the other hand, the object referred to by the left hand side reference counting pointer is deleted if, ``release''
returns 1, which it does if, and only if, the reference count goes to zero and the counter is deallocated. Since
``release'' also resets the counter pointer to zero, the assignment operator for ``counting_base'' does not
decrement the counter again. Instead it is simply assigned. After this the raw pointer value can safely be copied.
The access operators are all trivial and need no further explanation:
T* operator->() const
T& operator*() const
T* peek() const
Now only the ``manage'' member function remains:
template <class T>
inline void counting_ptr<T>::manage(T* t)
{
if (!t && release() || t && t != pt && reinit())
delete pt;
pt = t;
}
This one is only slightly tricky. If the parameter is the zero pointer, we want the reference count to also be the zero
pointer, and thus ``release'' is called. Otherwise we want the counter value to be 1, so ``reinit'' is called
instead. If either of those tells that the old counter is discarded, the object referred to is deallocated.

Efficiency
There is no question about it; there is a cost involved in using reference counting pointers. Every time an object is
allocated, a pointer is also allocated, and vice-versa for deallocation. Depending on how efficient your compiler's
memory manager is for small objects this cost may be negligible, or it may be severe. Every time a counting pointer
is assigned, constructed, destroyed and copied, counter manipulation is done, and that costs a few CPU cycles.

Exercises
• What happens if ``~T'' throws an exception?
• What happens if allocation of a new counter fails?
• The ``counting_base'' implementation and use is suboptimal. For example at destruction, the
``release'' member function is called twice, and the first time the counter pointer is set to zero to prevent
decrementing the counter twice. Improve the implementation to never (implicitly) set the pointer to zero
and yet always be safe.
• Does the public derivation from ``counting_base'' open up any holes in the type safety, despite that all
member functions are protected?

Coming up
If I missed something, or you want something clarified further or disagree with me, please drop me a line and I'll
address your ideas in future articles.
Next month is devoted to Run Time Type Identification (RTTI,) one of the new functionalities in C++.

Part Part Part Part Part Part Part Part Part Part1 Part1 Part1 Part1
1 2 3 4 5 6 7 8 9 0 1 2 3

Introduction
Lucky number thirteen will conclude the long C++ series. Last topic is Run Time Type Identification, or RTTI for
short. It's a new addition to C++. I do not have access to any compiler under OS/2 that supports RTTI, so the
example programs are written for, and tested with, the egcs compiler (a fast-moving bleeding edge gcc,) under
Linux.
RTTI is a way of finding out about the type of objects at run-time. There are two distinct ways this can be done. One
is finding a type identification for an object, giving a unique identifier for each unique type. Another is a clever cast,
which allows casting of pointers and references only if the type matches.
Towards the end of the article there is also a discussion about various aspects of efficiency in C++, especially in
comparison with C.

Type Safe (down)Casting


Many class libraries, most notably GUI libraries like IBM's Open Class Library, suffer from the problem that
callback functions will be called with pointers to objects of a base class, but you know the objects really are of some
class inheriting from it. For example, concider a button push event, from which you can get a pointer to the button
itself. Suppose a hierarchy like this:
class Event {};
class Window {};
class Control : public Window {};
class Button : public Control {};
class PushButton : public Button {
public:
class PushedEvent : public Event {
public:
PushButton* button(void) const;
};
void register(void (*pushed)(const PushedEvent&));
};
class TextPushButton : public PushButton {
public:
void setText(const char* txt);
};
The idea is that whoever uses a push button can register a function that will be called whenever a pushbutton is
called. Let us put it to use:
void pushed(const PushButton::PushedEvent& ev);
void createButton(const char* txt)
{
TextPushButton* pb=new TextPushButton();
pb->setText(txt);
pb->register(pushed);
}
void pushed(const PushButton::PushedEvent& ev)
{
TextPushButton* pb=(TextPushButton*)(ev.button());
// ^^^^^^^^^^^^^^
pb->setText("***");
}
This does not look too dangerous, does it? The callback is registered when the button is created, so we know it is the
right kind, and the down cast marked with ``^^^''is safe. Or is it? Right now it is, but as the program grows, it might
not be as easy to see what happens, and somewhere the wrong callback is registered for some button. The result is
likely an uncontrolled crash, or just generally weird behaviour. The solution is to do the cast only if it is legal. Here
is a new version of the ``pushed'' function using the RTTI ``dynamic_cast''.
void pushed(const PushButton::PushedEvent& ev)
{
TextPushButton* pb=
dynamic_cast<TextPushButton*>(ev.button());
assert(pb);
pb->setText("***");
}
``dynamic_cast<T>(p)'' works like this: If ``p'' is-a ``T'' the result is a ``T'' referring to the object, otherwise a
zero pointer is returned (of if ``T'' is a reference, the exception ``bad_cast'' is thrown.) That way we can check
and take some action if the function is called with a pointer or reference to the wrong type. There is one catch with
``dynamic_cast''. It works only if there is at least one virtual member function in the type casted from, otherwise
you get compilation errors. If you think about it, however, that is not much of a penalty. At least the destructor
should be virtual in such hierarchies anyway.
It must be stressed that this use of ``dynamic_cast'' can always be avoided (I cannot prove it, but I have never
seen a counter proof either, and many have tried.) The need arises from a poor design (the solution is to use dynamic
binding instead, by turning the problem ``inside-out''.) Sometimes we have to live with poor designs, however, and
then this can make our life a lot easier. It can also be used during a transition between different libraries. Here is an
example mirroring a problem from my previous job:
void print(ostream& os)
{
if (ostrstream* pos=dynamic_cast<ostrstream*>(&os))
{
*pos << ends;
cout << pos->str();
pos->freeze(0);
} else if(ostringstream*pos=
dynamic_cast<ostringstream*>(&os))
{
cout << pos->str();
} else throw bad_cast();
}
This transition is from the ``old'' ``ostrstreams'', storing strings as plain ``char*'', to the standard
``ostringstream'', which is based on standard strings. The difference lies in handling the end. An
``ostrstream'' holds a raw buffer of memory, and its end must be marked by appending a zero termination with
the ``ends'' modifier, while standard ``ostringstream'' returns a string object which itself knows how long it is
and a zero termination must not be added to it (otherwise an extra zero character will be printed.) However, never
design new code like this! Use this construct only during a transition phase. For new designs, use dynamic binding
instead.
In which way is this worse from the previous version that did not have the problem; where everything was always
``ostrstream''? Well, in no way. With RTTI we can live with both worlds at the same time, and we have added
an error check that should have been there earlier but was not because the language did not support it (what if the
function is called with an ``fstream'' object?)
Use RTTI ``dynamic_cast'' when being forced to adapt to poorly written libraries, as an error check, and during
transitions between libraries.

Identifying types
Much more interesting is using explicit information about the type of an object. This solves a problem that cannot
reliably be worked around with clever designs.
There is a standard class called ``type_info'', which purpose is to carry information about types. It is defined in
the header named <typeinfo> (note, no ``.h'') and looks as follows:
class type_info
{
public:
virtual ~ type_info();
bool operator==(const type_info&) const;
bool operator!=(const type_info&) const;
bool before(const type_info&) const;
const char* name() const;
private:
type_info(const type_info&);
type_info& operator=(const type_info&);
};
The ``name'' member function gives you access to a printable form of the name of the type identified by the
``type_info'' object. However, the standard requires very little of the ``name'' member function. Most notably it
is not standardised what the printable form looks like for any given type, even the built-in ones. In fact, it is not even
required that the string is unique for each type. This unfortunately means that you cannot write portable (across
compilers) applications that rely on the names in any way.
The ``before'' member function gives you a sort order for types. Do not try to get a meaning from the sort order,
there may not be one. It does not need to have any meaning, other than that it makes it possible to keep sorted
collections of type information objects.
You get a ``type_info'' object for a value through the built-in operator ``typeid(x)''. Note that it is the run-
time type of ``x'' that is accessed, not the static type. This requires a little bit of care. Say you have this situation:
class parent {};
class child : public parent {};
parent* p=new child();
cout << typeid(p).name() << endl;
cout << typeid(*p).name() << endl;
If we have a compiler whose name of a type as given from ``type_info'' is indeed the name of the type as we
write it in the program, what do you think the above snippet prints?
The answer is ``parent*'' followed by ``child''. This came as a surprise to me, but it makes sense. The run-time
type of ``p'' is ``parent*''. It is what it points to that may differ, and that is exactly what is mirrored by the output.

Is this useful?
Suppose you need to store and retrieve objects from a typeless media, such as a file, or a socket. Storing them is
easy, but when reading, you need to know what type of object to create. If you are designing a complete system
from scratch, you can add some type identifier to all classes, but this is error prone, since it is easy to forget
changing it when creating a new class inheriting from another one, and it does not work at all with existing classes.
Chances are you will be extending existing code, or decide to use third party class libraries.
Here is an outline for how to do this (in a non-portable, and slightly restricted way. Generality and portability
requires more work.)
First we design a class for I/O objects, let us call it ``persistent''. It may look like this:
class persistent
{
protected:
virtual void store(ostream& os) const = 0;
virtual void retrieve(istream& is) = 0;
};
The intention is that all classes we want to store must inherit from ``persistent'' and implement the ``store''
and ``retrieve'' member functions. This is limiting, but not as limiting as it may seem. We can still make use of
third party libraries; we just need to create persistent versions of the classes.
Next we need something that does the work of calling the member functions and creating the objects when read. Let
us call this class ``persistent_store''. It may be defined as follows:
class persistent_store
{
public:
persistent_store(iostream& stream);
template <class T>
void register_class<T>();
void store_object(persistent*);
persistent* retrieve_object();
};
The interface should be reasonably obvious. Obviously only classes inherited from ``persistent'' may be stored
and retrieved. Only classes registered with the store may be used. There will, however, be other requirements put on
the type ``T'', but what those will be will depend on our implementation. I have chosen the only additional
constraints to be that they have a default constructor and may be created on the heap with ''operator new''.
The use of template functions that do not have any parameters of the template type is a recent addition to C++ that
few compilers support. The syntax is a bit ugly, but it is not too bad. Here is how to use the persistent store:
class persistent_X : public X, public persistent
{
protected:
virtual void store(ostream& os) const {
os << *this;
};
virtual void retrieve(istream& is) {
is >> *this;
};
};
int main(int argc, char* argv[])
{
fstream file(argv[1]);
persistent_store storage(file);
storage.template register_class<persistent_X>();//*
persistent* pp=storage.retrieve_object();
persistent_X* px=dynamic_cast<persistent_X*>(pp);
storage.store_object(px);
}
The line marked ``//*'' shows the syntax for calling template member functions without parameters of the template
type. Note the ``template'' keyword. It is ugly, but I guess one gets used to it.
Now there are a number of problems that must be solved:
• How to prevent classes not inheriting from ``persistent'' from being registered
• How to allocate an object of the correct type on heap, given a string representation of its type.
• How to store the type information on the stream such that it can be interpreted unambigously.
The first is extremely easy to check for. Here is one way of doing it:
template <class T>
void register_class()
{
persistent* p = (T*)0;
...
};
Any attempt to call ``register_class'' with a type not publicly inheriting from ``persistent'' will result in a
compilation error. Not too bad.
The second problem, deciding the type from a name is easy to understand conceptually, but requires a bit of trickery
to implement.
The solution lies in using a map from strings to a creation function. A map is a data structure acting like an array,
but allowing any kind of indexing type. In this case the indexing type will be a string. Every string in the map
corresponds to a function accepting no parameters and returning a ``persistent*''. That is the easy part. So ...
the implementation of ``register_class'' may look like this:
template <class T>
void register_class()
{
persistent* p=(T*)0; // type check.
persistent* (*creator_func)(void) = ???;
creator_map.insert(make_pair(typeid(T).name(),
func));
};
Here the map type from the C++ standard library is used. The tricky part is to find out what ``???'' is. Perhaps it
comes as no surprise that the solution is yet another template, this time a function template.
template <class T>
persistent* persistent_object_creator(void)
{
return new T;
}
This function template implicitly carries out the type test for us (since ``T*'' can only be returned as
``persistent*'' if ``T'' publicly inherits from ``persistent''. In other words, ??? can be replaced with
``persistent_object_creator<T>'' and the check line can be removed.
Now for how to store and retrieve the type name. My suggestion is simple; store the length of the name followed by
the name itself. That way, when reading, the length can be read, a character buffer allocated for the correct size and
exactly that many characters read. When storing the string is checked for in the map to make sure no unregistered
types are stored. When reading, the creator function is looked up and called. Here is how it is all implemented:
void store_object(persistent* p)
{
const char* name=typeid(*p).name();
maptype::iterator iter=creator_map.find(name);
if (iter == creator_map.end())
throw "unregistered type";
medium << strlen(name) << ' ' << name;
p->store(medium);
};
persistent* retrieve_object(void)
{
size_t len;
medium >> len;
medium.get(); // read past blank.
char* name=new char[len+1];
medium.read(name,len);
maptype::iterator iter=creator_map.find(name);
delete[] name; // no longer needed
if (iter == creator_map.end())
throw "unregistered type";
persistent* p=(iter->second)();
p->retrieve(medium);
return p;
};
As can be guessed, the line ``if (iter == creator_map.end())'' checks if the lookup was successful. If
true the string was not represented in the map, and thus the type was not registered.
That is a mini persistency library for you. Enjoy.

C++ and Efficiency


I have once in a while heard things like ``C++ programs are slow and large compared to a C program with the same
functionality.'' In a way that statement is often true. Does it need to be that way? The answer is no, it does not. Here
is one very good argument for why. If you have a lean C design, the same design can be used with C++. If you do,
but use new and delete instead of malloc/free, use inline functions instead of macros and add constructors to
your structs, you are still better off than in plain C, because of the added type safety, but the program will not be
slower and larger.
As I see it, there are mainly two reasons for C++ bloat. One is a cultural problem, one is technical.

Culture related inefficiency


Let us first look at the cultural problem, because that is the one that is hardest to solve, and contributes most to the
bloat.
Throughout this course, I have been touting generality and extensibility over and over and over. However, not all
problems need general and extensible solutions. Generality and extensibility have a price. Are you prepared to pay
the price? It depends, right? If I can make use of the generality and extensibility at some other time, development-
time efficiency has been gained, possibly at the cost of program size and run-time efficiency.
Another cultural problem leading to inefficient C++ programs is the hunt for efficiency! Yes, it is true. Here are
some examples:
Virtual functions
I have heard people say things like ``As a performance optimization, I've removed all virtual functions and replaced
the virtual function calls with switch statements and ordinary member function calls.'' That is a major performance
killer. If you need the functionality that a virtual function call gives you, there is just no way to do it faster than
through a virtual function call. The switch switch/call construct is guaranteed to require at least as many instructions
(probably more) and is an instruction pipeline killer for the CPU, something that the virtual function call
interestingly is not.
Inline functions
While well chosen inline functions may speed up your program, ill chosen ones will lead to bloated executables, and
are likely to reduce the number of cache hits since active code areas will increase in size. Remember that an inline
function is actually not a function, strictly speaking. If inlined, the instructions for the function will be inserted at the
place of the call. If the function is large (more than a very few instructions) the size of your program will grow
considerably if the function is called often. More interesting is what happens if the compiler for one reason or
another fails to inline it. It will then have to make an out-of-line function for it, which will be called like normal
functions. There is one difference however (getting into the area of technical problems here, I will return to this one
shortly.) Where will the out-of-line function reside? With one exception, all compilers I know of will add one copy,
as a static function, for every translation unit (read .cpp file) where the function inlining failed. In a large program,
this might mean *many* copies, and since every copy is in its own memory area, you will not get the boost from
high performance hits due to good locality either.
Fear of template code bloat
Since it is ``a well known fact'' that templates leads to code bloat, many programmers avoid them. This means
rolling their own algorithms and collections instead of using standard ones. Unless, however, the programmer is a
top-notch algorithm and data-structure guru, the result is just about guaranteed to be slower, and quite possibly
larger, than those in the standard library. After all, the contents of the standard library are state of the art. Have a
look at the SGI STL, and read the documentation and code commens, and you will notice that many of the data
structures and algorithms used were not even known a year ago. How many programmers have a working
knowledge of the latest and greatest of algorithms and data structures?
Technical problems
The largest technical reason for slow C++ programs is compilers with very poor code optimizers. Most C++
compilers use exactly the same optimization techniques as C and Fortran compilers do, despite the fact that the way
a C++ program works and accesses memory etc. differs a lot. I know of one C++ compiler that has a code optimizer
made especially for the requirements of C++. It has been shown to equal and even beat Fortran for performance, and
that is when using good encapsulation and templates. When feeding it a program written like a C program,
performance will be poorer. If you are curious, look up KAI C++ (Note. I am not associated with them in any way. I
have used their compiler, that is all.) Unfortunately it is not available for OS/2, and I doubt it ever will be (bug them
about it, though, and it might happen.)
I mentioned earlier the problem of outlined inline functions. A good compiler will not leave you several copies as
static functions, but unfortunately many do.
A worse technical problem is exceptions. Some compiler vendors, and many proponents of exceptions, say that
exception handling can be implemented such that there is no performance loss at all, unless an exception is actually
thrown. It may seem like it, but it is not true. No matter how good the implementation is, exceptions add a number
of program flows that would otherwise not be there, and that makes life harder for the code optimiser.

Recommended reading
I want to finish by recommending some books on C++.
``Effective C++, 2nd ed'', Scott Meyers. A must read for any C++ programmer. Contains 50 tips, with examples and
discussions, for how to improve your programs. Meyers' writing style is easy to follow and entertaining too.
``More effective C++'', Scott Meyers, Another 35 tips, this time introducing cleverer optimisation techniques like
copy-on-write.
``Advanced C++, Programming Styles and Idioms'', James O. Coplien. Without doubt this book from 1992 is getting
old, but it contains many useful tecniques. It is a mind opener in many ways.
``Scientific and Engineering C++'', John J. Barton and Lee R. Nackman. Often simply referred to as B&N. This is a
modern ``Advanced C++''. What they have done is to break almost every rule of thumb, and as a result they have
extremely extensible, slick, type-safe and fast designs. Beware, however, this book is not for beginners.
``The Design and Evolution of C++'', Bjarne Stroustrup. This book answers all the why's. Why does C++ have
multiple inheritance? Why does it provide assignment, destruction, copy-constructor and default constructor for
you? Why is RTTI there? Why no garbage collection? Why not dynamic types like in Smalltalk?
``Ruminations on C++'', Andrew Koening and Barbara Moo. Now, this is a pleasant book to read. Koenig is the only
author I know who can explain a problem to solve, which one immediately realizes will require a large program,
present an easy to understand one page solution just to say it was unnecessarily clumsy and reduce it to half a page
without sacrificing extensibility and generality. Entertaining and enlightening.
Also, do follow comp.lang.c++.moderated.

Das könnte Ihnen auch gefallen