Our overview of C++ Standard Library, STL for short, covers its containers, iterators, and algorithms. Containers and iterators are C++ objects; the algorithms are functions. All STL components are C++ templates. That's where the abbreviation STL takes its origin - the Standard Template Library. An animation of STL components helps to visualize how objects interact at runtime. In C++ there are two kinds of templates: C++ template classes, such as std::vector, and C++ template functions, such as swap, sort, and so on. The idea of a template is to parameterize part of the program by types of variables. This is called generic programming, which presumes that a program will work correctly with any type. The typenames designated as template parameters themselves become 'variables' at compile time. While creating templates is one of the most challenging programming tasks in C++, using prefabricated templates from the STL library is quite easy: #include <vector> #include <string> using namespace std; int main (int argc, char* argv[]) { vector< double > vd; // vd elements are floating point numbers vector< int > vi; // vi elements are integer numbers vector< string > vs; // vs elements are string objects return 0; } The typenames which appear inside angled brackets are template parameters. Template function calls normally ommit template parameters, because the typenames of their template parameters are absorbed directly from the actual function parameters. However, template parameters of functions may also be specified by the programmer:
#include <cassert>
#include <algorithm>
using namespace std;
int main (int argc, char* argv[])
{
int one = 1;
int two = 2;
swap< int >( one, two ); // explicit template param
swap( one, two ); // implicit template param
assert( one == 1 );
assert( two == 2 );
return 0;
}
Note that because swap expects both arguments to be of the same type, it needs just one template parameter. While STL comes with every C++ compiler, the language permits development of the third-party libraries. Many more libraries exist besides STL. Free libraries can be found through various web directories. For example, Google has its own directory of C++ Class Libraries. |
Containers replicate structures commonly used in programming:
|
A stack is a container that permits to insert and extract its elements only from the top of the container: #include <cassert> #include <stack> using namespace std; int main (int argc, char* argv[]) { stack< int > st; st.push( 100 ); // push number on the stack assert( st.size() == 1 ); // verify one element is on the stack assert( st.top() == 100 );// verify element value st.top() = 456; // assign new value assert( st.top() == 456 ); st.pop(); // remove element assert( st.empty() == true ); return 0; } |
A set is a container that holds unique elements. The elements in std::set are always sorted. #include <cassert> #include <iostream> #include <set> using namespace std; int main (int argc, char* argv[]) { set< int > iset; // set of unique integer numbers iset.insert( 11 ); // populate set with some values iset.insert( -11 ); iset.insert( 55 ); iset.insert( 22 ); iset.insert( 22 ); if ( iset.find( 55 ) != iset.end() ) { // is value already stored? iset.insert( 55 ); } assert( iset.size() == 4 ); // sanity check :-) set< int >::iterator it; for ( it = iset.begin(); it != iset.end(); it++ ) { cout << " " << *it; } return 0; } // Output: -11 11 22 55 |
A map is a container that holds unique pairs of keys and values. The elements in std::map are always sorted by its keys. Each element of the map is formed by the combination of the key value and a mapped value. Map iterators access both the key and the mapped value at the same time. #include <cassert> #include <iostream> #include <string> #include <map> using namespace std; int main (int argc, char* argv[]) { map< string, string > phone_book; phone_book[ "411" ] = "Directory"; phone_book[ "911" ] = "Emergency"; phone_book[ "508-678-2811" ] = "BCC"; if ( phone_book.find( "411" ) != phone_book.end() ) { phone_book.insert( make_pair( string( "411" ), string( "Directory" ) ) ); } assert( phone_book.size() == 3 ); map< string, string >::iterator it; for ( it = phone_book.begin(); it != phone_book.end(); ++it ) { cout << " " << it->first << " " << it->second << endl ; } return 0; } /* Output: 411 Directory 508-678-2811 BCC 911 Emergency */ |
An #include <cassert> #include <string> #include <utility> using namespace std; int main (int argc, char* argv[]) { pair< string, string > strstr; strstr.first = "Hello"; strstr.second = "World"; pair< int, string > intstr; intstr.first = 1; intstr.second = "one"; pair< string, int > strint( "two", 2 ); assert( strint.first == "two" ); assert( strint.second == 2 ); return 0; } Functions that need to return two values often return a pair: pair< bool, double > result = do_a_calculation(); if ( result.first ) do_something_more( result.second ); else report_error(); |
An iterator is an object that provides access to objects stored in STL containers. The entire concept of C++ pointer is crucial to understanding general semantics of iterators, because iterators are designed to behave like C++ pointers. For example, #include <iostream> #include <vector> using namespace std; int main (int argc, char* argv[]) { vector< int > vint( 3 ); // vector with 3 integer numbers vint[ 0 ] = 10; vint[ 1 ] = 20; vint[ 2 ] = 30; // Display elements of the vector: vector< int >::iterator it; for ( it = vint.begin(); it != vint.end(); ++it ) { // Like pointer, iterator is dereferenced to // access the value of the element pointed by it: cout << " " << *it; } return 0; } // Output: 10 20 30 STL library is also using the iterator concept for iterator adaptors. For example, back_insert_iterator inserts an object after the last element of a container: #include <iostream> #include <vector> #include <algorithm> using namespace std; int main (int argc, char* argv[]) { vector< int > vdummy; // vector with no elements vector< int > vint( 3 ); // vector with 3 integer numbers vint[ 0 ] = 1; vint[ 1 ] = 2; vint[ 2 ] = 3; // insert values from vint into dummy: back_insert_iterator< vector< int > > inserter( vdummy ); copy( vint.begin(), vint.end(), inserter ); // Display results: for ( int idx = 0; idx < vdummy.size(); ++idx ) { cout << " " << vdummy[ idx ]; } return 0; } // Output: 1 2 3 |
A string is STL container designed to accommodate sequence of characters, that is, text. Strings provide built-in features to operate on fragments of text in a more intuitive way than zero-terminated character arrays, commonly known as C-strings. For example, #include <cassert> #include <string> using namespace std; int main (int argc, char* argv[]) { string str( "Hello" ); for ( int idx = 0; idx < str.length(); ++idx ) { // Access and modify individual characters: str[ idx ] = toupper( str[ idx ] ); } assert( str == "HELLO" ); str.append( 3, '!' ); // add three exclamation points assert( str == "HELLO!!!" ); int pos1 = str.find( "L" ); // HELLO!!! int pos2 = str.rfind( "L" ); // || assert( pos1 == 2 ); // pos1-''-pos2 assert( pos2 == 3 ); // Get 2-character long substring starting at pos1: assert( str.substr( pos1, 2 ) == "LL" ); str.replace( pos1, 3, "YDAY" ); // HE...!!! assert( str == "HEYDAY!!!" ); // '-----pos1 return 0; } |