C++ standard class libraries

Now that we are familiar with classes, we will introduce the various "stock" C++ classes: string, stack, queue, list, and vector.


The string class

First, we need to #include <string> (NOT cstring or string.h, they are quite different!)

Now we can declare variables to be of type string, e.g.

string s1, s2, s3;
This class provides a number of constructors and other methods, as well as a number of overloaded operator definitions. All of these allow for more flexible, and safer, manipulation of strings than the traditional char * format.

Internally, the string class stores the string as a null-terminated character array (as per our usual idea of strings), but also has a field indicating the size of the array. This allows the string class to ensure operations never run off the end of a string.

The string class also contains a number of routines which allow us to dynamically change the size of a string - again providing much more flexible handling.

In the sections below we outline a number of the key string methods. There are many more methods than this, but this provides a reasonable introduction.

Constructors

The default constructor, string(), creates an empty string. E.g.
string s1; // s is empty

We can initialize the string with a character array, e.g.
string s2("blah"); // s2 gets initializes as a 5-char array
// with a null terminator inserted

We can initialize a string from another string, e.g.
string s3(s2);

We can initialize a string as a repeated sequence of characters, e.g.
string s4(6, 'm'); // s4 contains "mmmmmm"

Overloaded operators

The assignment operator copies values (as usual), i.e. copies the appropriate string, and allocates the size appropriately
s1 = s2; // s1 gets a copy of s2 (array and size)
s1 = "blah";
s1 = 'x';

The traditional comparison operators have all been overloaded to compare strings, e.g.
if ((s1 == s2) && (s3 < s4)) {

The + operator is used for append, e.g.
s1 += s2; // append a copy of s2 to the end of s1
s3 = s1 + s2; // s3 gets a copy of s1 followed by a copy of s2
s1 += "blah"; // append "blah" and adjust the size of s1
s1 += 'x'; // append "x" and adjust the size of s1

Other methods

We can reset a string's values based on a substring of another,
s1.assign(s2, 1, 2); // copy the first 2 chars of s2 to s1,
// starting at position 1 of s1

We can insert a string inside another, e.g.
s1.insert(2, "foo"); // insert "foo" starting at position 2 of s1

We can change the size of the string (i.e. allocate more or less space for its array), e.g.
s1.resize(20); // s1 now has maximum size 20

We can determine the current length of the string (i.e. the length up to the null terminator, which is less than or equal to the total allocated space)
int len = s1.length();

We can get just the array part back using the c_str method, e.g.
char *sptr = s1.c_str();

We can search a string for the position at which a substring starts using the find method, e.g.
pos = s1.find(s2); // search s1 for substring s2
pos = s1.find("blah"); // search s1 for substring "blah"

The list class

We must #include <list>, and we then have the following operations available:
bool empty(); // is the list empty?
list_type back(); // return a copy of the back element
list_type front(); // return a copy of the front element
void merge(anotherlist); // merge in the contents of another list
void pop_front(); // remove the front element
void push_front(element); // add an element at the front
void push_rear(element); // add an element at the back
void remove(element); // remove ALL occurrences of the element
void reverse(); // reverse the order of the list
int size(); // get the current number of list elements
void sort(); // sort the list elements (ascending order)
void swap(anotherlist); // swap this list's contents with the other list's
We can create lists of any kind of element, but to create and use them we must specify what specific kind of elements they use. (These are called templated classes.)

For instance, to create a list of integers we use the syntax
list<int> I
Note that the list of operations above would then use the appropriate data type, for instance the back and front functions would return an int, the push_ functions would expect to be passed an int, etc.

Similarly, to create a list of floats and a list of strings the syntax would be
list<float> F
list<string> S
(The I, F, S are just variable names, you can pick any names you like for those.)

Thus to test if a list is empty we might use
if (I.empty()) {
or to push a value onto the end of the list we might use
I.push_rear(37);


The queue class

Queues are much like lists, but generally we assume items are added to the back and removed from the front.

We must #include <queue>, and we then have the following operations available

bool empty(); // is the queue empty?
queue_type back(); // returns a copy of the back element
queue_type front(); // returns a copy of the front element
void pop(); // dequeues (removes) the front element
void push(element); // enqueues the new item at the back
int size(); // get the current number of queued elements
Again, this is a templated class.

The vector class

We must #include <vector>, and then this class effectively operates like an array class, but with support for applying operations to the elements sequentially. It is another templated class, and the operations available to us include:
vector_type back(); // return a copy of the last vector element
vector_type front(); // return a copy of the first vector element
bool empty(); // is the vector empty?
void pop_back(); // remove the back element
void push_back(element); // add an element to the end of the vector
int size(); // get the current number of vector elements
We can set the vector size and initial element values using the constructor, and we can also access the vector elements using the square bracket notation, e.g.
vector<int> vec1(30,-1); // create a 30-element vector,
                         // initialize all elements to -1
vec1[7] = 45;

Iterators with the templated classes

Most of the templated classes support the use of iterators.

These are generalizations of pointers, and allow you to cycle through the elements of the class with the use of ++ and --.

The classes include a begin() and end() method for the iterators and overload the ++ -- == != operators for the iterators.

An example of iterator use is shown below:


vector<int>  myvec;

std::vector<int>::iterator p;  // p will act like a pointer to a 
                               // single int within the vector

p = myvec.begin();  // p points at the first int in the vector

// set up a while loop to cycle through the vector contents,
//     one int at a time
while (p != myvec.end()) 
{
   int nextdata = (*p);       // make nextdata point at the current int
   printf("%d\n", nextdata);  // print it out
   p++;                       // make p point at the next int
}
Note the syntax for declaring an iterator:
std::classname<contenttype>::iterator variablename;
For example, below we create iterators for a variety of class types:
// declare some variables
list<int> L;
queue<float> Q;
vector<string> V;

// declare some appropriate iterator variables
std::list<int>::iterator my_list_iterator;
std::queue<float>::iterator my_queue_iterator;
std::vector<string>::iterator my_vector_iterator;
Note that you can also use reverse_iterator instead of iterator, which allows you to cycle through the data in reverse order.

You can also use const_iterator, which (on dereferencing) gives you a read-only copy of the data element.