In last month's issue of Borland C++ Developer's Journal, we gave you a brief review of the new Standard Template Library, or STL, and described its structure of containers, iterators, and algorithms (Standard C++ - Standard Template Library overview). Elsewhere in the same issue, we contrasted the STL with the Borland International Data Structures (BIDS) template-based container class library (Using Standard Template Library (STL) containers and iterators).
If you're familiar with the BIDS classes, you probably won't have much trouble learning to use the STL classes. However, even if you're accustomed to using the BIDS template classes, the STL takes a dramatically different approach to manipulating objects in a container.
If you're not familiar with the BIDS classes, you may find them overwhelming. In comparison, you'll find the STL has a simpler architecture, but its use of global template functions and special, nested type names may seem unorthodox.
In this article, we'll give you a better understanding
of how the STL classes work together. To demonstrate the flexibility
of the STL classes and to illustrate the STL's organization,
we'll create an STL-derived replacement for the BIDS class
template TArrayAsVector<>, and we'll build
an example program that exercises some of the primary member functions.
Then, we'll walk through each replacement class's
member functions to describe how they use the features of the
STL to simulate the TArrayAsVector<> class.
To begin, launch the Borland C++ Integrated Development Environment (IDE). When the IDE's main window appears, choose New Project... from the Project menu.
In the New Project dialog box, enter \STL_BIDS\STL_BIDS.IDE in the Project Path and File Name entry field. Then, select EasyWin [.exe] in the Target Type list box and click OK to create the project.
When the STL_BIDS.IDE project window appears, right-click on the name stl_bids [.def] and choose Delete Node from the pop-up menu. In the confirmation dialog box that appears, click Yes to delete this node from the project.
If the name stl_bids [.rc] appears in the project window, right-click on that name and choose Delete Node from the pop-up menu. Click Yes in the confirmation dialog box.
Choose New from the file menu. When the new editing window appears, enter the code that appears in Listing A. When you finish entering the code, choose Save As... from the File menu, enter the filename \STL_BIDS\STL_BIDS.H in the File Name entry field and click OK.
Next, double-click on the name stl_bids [.cpp] in the project window. When the editing window for this file appears, enter the code from Listing B on page 5. When you finish entering the code, choose Save from the File menu.
Listing B: STL_BIDS.CPP
#include <iostream.h> #pragma hdrstop #include "stl_bids.h" //#include <include\classlib\arrays.h> void displayAll(TArrayAsVector<long>& a) { for(int count = a.LowerBound( ); count < a.LowerBound( ) + a.GetItemsInContainer( ); ++count) { cout << count << " " << a[count] << endl; } cout << "# Items = " << a.GetItemsInContainer( ) << endl << endl; } int main( ) { TArrayAsVector<long> array(10, 5, 1); array.Add(5l); array.Add(6l); displayAll(array); array.AddAt(12, 12); displayAll(array); cout << "Found 6 @ " << array.Find(6) << endl; array.Destroy(6l); displayAll(array); if(array.HasMember(12)) cout << "Has 12" << endl; array.Reallocate(100, 3); displayAll(array); if(array.IsFull( )) cout << "Full" << endl; array.Flush( ); displayAll(array); return 0; }
Before we run the example program, let's take a closer
look at each of the mem-ber functions that our TArrayAsVector
class provides (we'll show the member functions in boldface
type). In doing so, you'll see the type of code you might
write if you use the STL classes instead of the BIDS classes.
In reviewing this replacement version of the TArrayAsVector class, let's begin by examining the constructor. The BIDS version of this class contains a delta parameter in the constructor that determines how quickly an object of this class will grow when you resize it.
Since the vector class doesn't support fixed size containers (nor does it allow you to adjust the resizing algorithm), we've provided the data member growable, which keeps track of whether the container is resizeable. In the constructor TArrayAsVector( ), we set this value, along with the zero-offset lowerbound, and reserve enough storage space based on the difference between the parameters upper and lower.
In the destructor, ~TArrayAsVector( ), we simply call the base class destructor, ~vector( ), to deallocate the storage for the container. (We have to call this destructor explicitly, since the vector class doesn't de-clare the destructor as virtual.)
The Add( ) member function inserts a new item at the end of the container (if the container isn't full). Similarly, the AddAt( ) member function inserts a new item at a particular location in the container. (If the container doesn't yet contain the specified location, this function resizes the container as necessary.)
The ArraySize( ) member function simply returns the current capacity of the container. Typically, this will be equal to the number of items in the container (see GetItemsInContainer( )). However, the STL vector class contains the member function reserve( ), which allocates extra space for the container that's beyond what it currently needs.
The BoundBase( ) member function is a simple utility function for the class. If you create an array that doesn't start at index 0, this function returns the actual index of an element. Similarly, the ZeroBase( ) member function converts a normalized index value to a value relative to 0.
We've provided two versions of the Detach( ) and Destroy( ) member functions, just like the BIDS class does. The first ver-sions remove an object from the container based on its index position. The second ver-sions find and remove an object based on its value. The RemoveEntry( ) member function provides another name for the Detach( ) func-tion for backward compatibility with earlier versions of the BIDS classes.
The Find( ) member function illustrates how the STL container class templates, iter-ator classes and types, and algorithm func-tion templates work together. The begin( ) and end( ) member functions from the vector class return iterators to those locations in the container. The find( ) function template searches the container for the specified item, using those iterators as guides.
The Flush( ) member function destroys each object in the container and resets the size of the container to zero. Note, however, that this function doesn't change the capacity of the container (the amount of space you've allocated for it).
The GetItemsInContainer( ) member function returns the current number of objects the container holds by calling the vector class's size( ) member function. Unfortunately, many people confuse the original BIDS TArrayAsVector version of this function with the ArraySize( ) member function.
The Grow( ) member function allows you to adjust the amount of space the container allocates for its objects. Internally, this function calls the Reallocate( ) member function to adjust the storage space.
The HasMember( ) member function pro-vides a simple wrapper around locating an object in the container. Internally, this function calls the Find( ) member function and returns 1 if the item is present in the container and 0 if it isn't.
The IsEmpty( ) and IsFull( ) member functions allow you to easily determine whether the container has any elements or if its size is equal to its capacity. If the container has the growable flag set, the IsFull( ) function will always return 0, since vector class containers will resize by default.
The LowerBound( ) and UpperBound( ) mem-ber functions allow you to determine the beginning and ending index values for the container. (By specifying a nonzero value for the lower parameter in the constructor, you can simulate Pascal-style arrays that don't begin at 0.)
To simulate built-in arrays, we've overloaded operator [] and operator [] const for the class TArrayAsVector. The const version of this operator allows you to retrieve values from a const container. The SetData( ) member function simply calls operator [] to set the value of a specific element.
The Reallocate( ) member function is a more primitive
form of the Grow( ) function. One dif-ference between
them is that the Reallocate( ) function allows you
to readjust the starting index of the array by specifying a nonzero
value for the offset parameter.
To build and run STL_BIDS.EXE, choose Run from the Debug menu. When the program runs, you'll see the output from Figure A appear in the EasyWin output window. By the way, you'll need to make sure that the STL header files are in the INCLUDE path for this project. To add the path for the directory that contains these files, choose Project... from the Options menu, append the appropriate directory path to the information in the Include entry field of the Source Directories sec-tion, and click OK.
Figure A - You'll see this output appear when you run the STL_BIDS.EXE program.
5 5 6 6 # Items = 2 5 5 6 6 7 (random number) 8 (random number) 9 (random number) 10 (random number) 11 (random number) 12 12 # Items = 8 Found 6 @ 6 5 5 6 (random number) 7 (random number) 8 (random number) 9 (random number) 10 (random number) 11 12 # Items = 7 Has 12 5 (random number) 6 (random number) 7 (random number) 8 5 9 (random number) 10 (random number) 11 (random number) # Items = 7 # Items = 0
Even though this program isn't an exhaustive test, it does
show that you can use our STL-compatible version of the TArrayAsVector
class in much the same way you'd use the BIDS version.
In fact, you can compare the behavior of the BIDS version quite
easily. To do so, change lines 4 and 5 to become
//#include "stl_bids.h" #include "\bc45\include\classlib\arrays.h"
This will enable the standard BIDS version of this class. (If
you're using Borland C++ 4.0, be sure to use \BC4 instead
of \BC45 as the beginning of the path and filename in this #include
directive.) When you rerun the program, you'll see the
same output as before, except the random number values will change.
Copyright (c) 1996 The Cobb Group, a division of Ziff-Davis Publishing Company. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of Ziff-Davis Publishing Company is prohibited. The Cobb Group and The Cobb Group logo are trademarks of Ziff-Davis Publishing Company.