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

Stack with constructors & destructors

Reimplementing the linked list (inside Stack) with constructors and destructors shows up a significant problem. Here’s the modified header file:

//: C06:Stack3.h
// With constructors/destructors
#ifndef STACK3_H
#define STACK3_H

class Stack {
  struct Link {
    void* data;
    Link* next;
    Link(void* dat, Link* nxt);
    ~Link();
  }* head;
public:
  Stack();
  ~Stack();
  void push(void* dat);
  void* peek();
  void* pop();
};
#endif // STACK3_H ///:~

Not only does Stack have a constructor and destructor, but so does the nested class Link:

//: C06:Stack3.cpp {O}
// Constructors/destructors
#include "Stack3.h"
#include "../require.h"
using namespace std;

Stack::Link::Link(void* dat, Link* nxt) {
  data = dat;
  next = nxt;
}

Stack::Link::~Link() {
  delete data;
}

Stack::Stack() { head = 0; }

void Stack::push(void* dat) {
  head = new Link(dat,head);
}

void* Stack::peek() { return head->data; }

void* Stack::pop() {
  if(head == 0) return 0;
  void* result = head->data;
  Link* oldHead = head;
  head = head->next;
  delete oldHead;
  return result;
}

Stack::~Stack() {
  Link* cursor = head;
  while(head) {
    cursor = cursor->next;
    delete head;
    head = cursor;
  }
  head = 0; // Officially empty
} ///:~

The Link::Link( ) constructor simply initializes the data and next pointers, so in Stack::push( ) the line

head = new Link(dat,head);

not only allocates a new link (using dynamic object creation with the keyword new, introduced earlier in the book), but it also neatly initializes the pointers for that link.

Because the allocation and cleanup are hidden within Stack – it’s part of the underlying implementation – you don’t see the effect in the test program:

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

int main(int argc, char* argv[]) {
  requireArgs(argc, 1); // File name is argument
  ifstream in(argv[1]);
  assure(in, argv[1]);
  Stack textlines;
  string line;
  // Read file and store lines in the stack:
  while(getline(in, line))
    textlines.push(new string(line));
  // Pop the lines from the stack and print them:
  string* s;
  while((s = (string*)textlines.pop()) != 0) {
    cout << s << endl;
    delete s; 
  }
} ///:~

The constructor and destructor for textlines are called automatically, so the user of the class can focus on what to do with the object and not worry about whether or not it will be properly initialized and cleaned up.

Contents | Prev | Next


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