The Standard Template Library

and

a few details on how it is implemented

 

A example container class

•      Our Example container class is called Linked

–    It is a “toy” class, not part of the STL

–    We look at it as an example of how container classes are implemented in the STL

•      We will start with a client’s view…what the class needs to provide to users.

•      Since we don’t know what the data type of our client is, we must make our class a template

•      Lists  will be instantiated like this:
   Linked<int> intList;   or
   Linked<Employee> employeeList;

 

Overall view of Linked class

•      Our Linked class will be made up of these parts

–    The data members

•    An embedded struct to hold the node

–   The struct will have two parts: a generic item, and a pointer to the next node

•    The private data members of the class

–   a pointer to the head of the list and
–   an int to keep track of how many items are in the list

•    A nested Iterator class

–   Must define all the operations for traversing and comparing a linked list
–   Some of these will be overloaded operators

–    The member functions (limited for now)

•    A constructor, push_front, size, begin, end

 

Linked’s  struct & data members

template<class T> 
class Linked
{ protected:
        struct Node 
// data members of structs are public
          {   T item;           Node* next;       };  //end struct Node
      Node* head;
      long length;

•     
      
//  member functions, etc. go here
       class Interator {…all its data & member functions };

};  // end class Linked

 

The Linked class functions

•      For our toy class, we will only specify five member functions

•      Prototypes of member functions:

•      template<class T>  //or Comparable or whatever
class Linked
{  protected:
        struct Node 
// data members of structs are public
          {   T item;           Node* next;       };  //end struct Node
      Node* head;
      long length;

     class Interator {…all its data & member functions };  

 

       public    
            Linked( ); //  constructor makes empty list          
            long size( ) const; //returns the number of items in the list       
            void push_front(const T& newItem); //  inserts a new item at the front of the list     
            Iterator begin( ); // returns an iterator positioned at the front of the list         
            Iterator end( ); // returns an iterator positioned just after the end of the list

};

 

Implementing Linked’s member functions

•      The Node struct
struct Node
{   T          item;
     Node*  next;  }

 

•      The constructor
Linked( )
{   head = NULL;
     length = 0;  }

 

•      The size member function
   long size( ) const
   {  return length;}

 

•       The push_front member function  inserts a new item at the front of the list
   void push_front(const T& newItem)

       {  Node * temp = new Node;
       temp->item = newItem;
       temp->next = head;
       head = temp;
       length++;
    }

•      The begin member function will return a  iterator positioned at the front of the list
   Iterator begin( )
   {   return Iterator(head);  }

•      The end member function will return a  iterator positioned at the end of the list
   Iterator end( )
   {   return Iterator(NULL);   }

 

 

Iterators for Linked class

•      An iterator is an object that allows the client to access each item in the container.

•      An iterator class is embedded in almost every container class

•      The iterator class has member function to overload these four operators

–    operator ++ advances the calling iterator object to the next item in the container

•    There are pre and post increment operators

–    operator* dereferences the item where the iterator is currently positioned

–    Operator = = and != to test for equality

 

An example using Linked

int main( )

{     Linked<float> salaryList;

       float salary,  total = 0.00;
   cout << "Please enter a salary; the sentinel is -1.00: ";
   cin >> salary;

       while (salary != -1.00)
    {    salaryList.push_front (salary);

              total += salary;
          cout <<"Please enter a salary; the sentinel is -1.00: ";
          cin >> salary;          }

        float average;
    if (salaryList.size( ) > 0) 

                  average = total / salaryList.size( );

        cout << "Here are the above-average salaries:" << endl;

        Linked<float>::Iterator itr;
    for (itr = salaryList.begin( ); itr != salaryList.end( ); itr++)

             if (*itr > average)
                cout << *itr << endl;

}
     

   

What private data members will the class Iterator need?

–   It will need a pointer to a Node.

 

Implementation of Iterator

•      The Iterator class has only one data member

protected:

    Node* nodePtr;   // a pointer to a Node
    Iterator (Node* newPtr)       
     {         nodePtr = newPtr;           }
// this constructor should be protected (or private)

public: 
    Iterator( )         {       }
// default constructor

 

Implementing the member functions of the Iterator class

•      Overloading the = = operator.
 bool operator== (const Iterator& itr) const
{return nodePtr = = itr.nodePtr;  } // overloading = =

 

•      Overloading the != operator
bool operator!= (const Iterator& itr) const  
 {  return nodePtr != itr.nodePtr;    }
    // overloading !=

 

•      Overloding the * (dereference) operator
T& operator*( ) const      
{     return nodePtr
> item;      } // overloading *

 

The ++ (increment) operator

•      The compiler must be able to tell the difference between post increment and pre increment

–   It cannot do this if their signatures are the same

–   So the post increment operator’s signature includes an int argument; this is a dummy argument, solely for the compiler’s sake

Iterator operator++(int)  // post increment uses a dummy argument
Iterator operator++( ) 
// preincrement has no argument

 

Look at pre and post increment

•      Suppose you have this statement
     num = ++I + num;

•      How is it different than this statement
     num = I ++ + num;

•      To see, give num and I values

•      Post increment is not done until AFTER the statement completes execution, so the I used in the statement has not been incremented.

 

Implementing the member functions of the Iterator class (cont)

•     Post increment operator
Iterator operator++(int)
{    Iterator temp = *this;      
      nodePtr = nodePtr
> next;        
      return temp;    
}
// postincrement ++

•     Pre increment operator
Iterator& operator++( )
{      nodePtr = nodePtr
> next;
         return *this;
}
// preincrement ++

 

Additional member functions of Linked

•      So far we have implemented five member function for Linked:  Linked( ), size( ) push_front( ), begin( ) and end( )

•      What other functions would be necessary or desirable?

–   Delete from the front of the list

–   Overload the assignment operator

–   Implement a destructor

–   Implement a copy constructor

 

IN class assignment (quiz)

•      Get together in groups of two or three

•      Look over than handout which has implemented the code we have been talking about

•      Write the code for member functions of the class Linked to do the following:

–   Delete from the front of the list

–   Overload the assignment operator

–   Implement a copy constructor

–   Implement a destructor

 

Implementing pop_front

•      What should it return? What are the arguments?

•      We need a temporary pointer to point to the first node in the list

•      We then make head point to the second node in the list

•      Then we delete the node pointed to by the temporary pointer

•      Then we decrease length.

 

How should operator= be overloaded?

•      How it would be used:

–    Assume Linked<Employee> Kmart and
Linked<Employee> WalMart have been declared and populated.

–    An assignment statement would look like this:
WalMart = Kmart;  Will a shallow copy work?

•      How should it be implemented?

–    First, we must delete all the nodes in the WalMart list.  Why?

–    Next, we must we need to copy the Kmart’s nodes to the WalMart’s list.

•    We can traverse through Kmart’s list, copying each node as we go, using push_front(temp->item )

–   Use a for loop to do this

•    Problem?  The list will be reversed

•    So then, we must copy it back to get it in the same order

•    This means we must use a temporary list for the first copy

 

Implementation of operator=

void operator= (const Linked<T>& rhsList)

 {     Linked<T> tempList;   // for the reversed list

        Node* temp;          

         while (head != NULL)      
                 pop_front( );         
// Destroy the calling object:

             for (temp = rhsList.head;  temp != NULL;  temp = temp > next)

                     tempList.push_front (temp > item);

 

        for (temp= tempList.head; temp != NULL;  temp = temp > next)

                push_front (temp > item);     

  } // overloading =

 

Implementation of the copy constructor

•      It is just like the assignment operator, except no list has to be destroyed.

 

The destructor

•      Destructors return to the operating system the dynamic memory a program requested.

•      They are automatically called for an object when that object goes out of scope.

–    This relieves the programmer from having to remember to delete dynamic objects when those objects go out of scope.

•      There are several ways to implement the destructor for Linked:

–    Traverse the list with a for loop, deleting each node as we go

–    Call pop_front( ) until head is NULL

•      Destructors should be written for classes whose objects contain dynamically allocated memory.

 

Overloading the assignment operator and copy constructor

•      The assignment operator and copy constructor needs to be overloaded for classes that have data members that contain pointers.

•      What is the difference between them? they both make copies

–   The copy constructor is used when one objects already exists, and we want to create another object that is a copy of it

–   The assignment operator is used when both objects already exist, and we want to copy one into another

 

Example of copy constructor and assignment operator

•      Suppose we have an object of type Linked<Person> that already has some data in it.

    Linked<Person> yourList;  // assume already has data

•      We want to create another list that is a copy of yourList.  We use a copy constructor

   Linked<Person> myList(yourList);

 

•      I have introduced errors into mylist, and I want to start over, copying yourList.  Use the assignment statement

   myList = yourList;