Bruce Eckel's Thinking in C++, 2nd Ed Contents | Prev | Next

Stash with constructors and destructors

The examples from previous chapters have obvious functions that map to constructors and destructors: initialize( ) and cleanup( ). Here’s the Stash header using constructors and destructors:

//: C06:Stash2.h
// With constructors & destructors
#ifndef STASH2_H
#define STASH2_H

class Stash {
  int size;      // Size of each space
  int quantity;  // Number of storage spaces
  int next;      // Next empty space
  // Dynamically allocated array of bytes:
  unsigned char* storage;
  void inflate(int increase);
public:
  Stash(int size);
  ~Stash();
  int add(void* element);
  void* fetch(int index);
  int count();
};
#endif // STASH2_H ///:~

The only member function definitions that are changed are initialize( ) and cleanup( ), which have been replaced with a constructor and destructor:

//: C06:Stash2.cpp {O}
// Constructors & destructors
#include "Stash2.h"
#include <iostream>
#include <cassert>
using namespace std;
const int increment = 100;

Stash::Stash(int sz) {
  size = sz;
  quantity = 0;
  storage = 0;
  next = 0;
}

int Stash::add(void* element) {
  if(next >= quantity) // Enough space left?
    inflate(increment);
  // Copy element into storage,
  // starting at next empty space:
  int startBytes = next * size;
  unsigned char* e = (unsigned char*)element;
  for(int i = 0; i < size; i++)
    storage[startBytes + i] = e[i];
  next++;
  return(next - 1); // Index number
}

void* Stash::fetch(int index) {
  assert(0 <= index && index < next);
  // Produce pointer to desired element:
  return &(storage[index * size]);
}

int Stash::count() {
  return next; // Number of elements in CStash
}

void Stash::inflate(int increase) {
  assert(increase > 0);
  int newQuantity = quantity + increase;
  int newBytes = newQuantity * size;
  int oldBytes = quantity * size;
  unsigned char* b = new unsigned char[newBytes];
  for(int i = 0; i < oldBytes; i++)
    b[i] = storage[i]; // Copy old to new
  delete [](storage); // Old storage
  storage = b; // Point to new memory
  quantity = newQuantity;
}

Stash::~Stash() {
  if(storage != 0) {
   cout << "freeing storage" << endl;
   delete []storage;
  }
} ///:~

Looking at inflate( ), you might ask why the “primitive” assert( ) is still being used after the require.h functions have already been introduced. The distinction is important: in this book, assert( ) will be used to watch for programmer errors. This makes sense because the output of a failed assert( ) is not particularly end-user friendly and should only be seen by programmers, while the require.h functions (which will be shown later in the book) are specifically designed to be reasonably useful for end-users.

Because inflate( ) is private, the only way an assert( ) could occur is if one of the other member functions accidentally passed an incorrect value to inflate( ). If you are certain this can’t happen, you could consider removing the assert( ), but you might keep in mind that until the class is stable, there’s always the possibility that new code might be added to the class which could cause errors. The cost of the assert( ) is low (and can be removed by defining NDEBUG) and the value of code robustness is high.

Notice, in the following test program, how the definitions for Stash objects appear right before they are needed, and how the initialization appears as part of the definition, in the constructor argument list:

//: C06:Stash2Test.cpp
//{L} Stash2
// Constructors & destructors
#include "Stash2.h"
#include "../require.h"
#include <fstream>
#include <iostream>
#include <string>
using namespace std;

int main() {
  Stash intStash(sizeof(int));
  for(int i = 0; i < 100; i++)
    intStash.add(&i);
  for(int j = 0; j < intStash.count(); j++)
    cout << "intStash.fetch(" << j << ") = "
         << *(int*)intStash.fetch(j)
         << endl;
  const int bufsize = 80;
  Stash stringStash(sizeof(char) * bufsize);
  ifstream in("Stash2Test.cpp");
  assure(in, " Stash2Test.cpp");
  string line;
  while(getline(in, line))
    stringStash.add((char*)line.c_str());
  int k = 0;
  char* cp;
  while((cp = (char*)stringStash.fetch(k++))!=0)
    cout << "stringStash.fetch(" << k << ") = "
         << cp << endl;
} ///:~

Also notice how the cleanup( ) calls have been eliminated, but the destructors are still automatically called when intStash and stringStash go out of scope.

Contents | Prev | Next


Contact: webmaster@codeguru.com
CodeGuru - the website for developers.
[an error occurred while processing this directive]