|
| Thursday, November 2, 2006 |
| The Standard Template Library |
C++ Standard Library
History
- C++ began a standardization process in 1989
- Standards define exact content and behavior of C++
- Standards makes it easier to...
- port C++ programs to different platforms
- use C++ in applications
- teach C++
- The standardization process was completed in 1997
- Made an international standard in 1998
- The standardization process included the development of a library
- Core language and the C++ library were standardized in parallel
- Part of the standard, this became known as the C++ standard library
Introduction
- This library extends the core language to provide some general components
- The library leverages and uses C++'s ability to program new abstract types
- The library makes extensive use of one of C++'s "newer" features, templates
- In fact, almost all parts of the library are written as templates
- The library provides a set of common classes and interfaces
- Gives programmers a higher level of abstraction by providing...String types Different containers (data structures such as linked lists, dynamic arrays, ...) Different algorithms (such as different sorting, searching algorithms) Numeric classes (such as complex numbers) I/O classes (we've already looked at this - C++ stream library) Classes for internationalization support (different character sets)
General Concepts
- Fundamental concepts of C++ standard library
- Needed to work with all or most of the components
NamespacesIntroduction
- More and more software is written as libraries, modules, or components
- Combining user code with such software could result in a problem
- What if you named your class the same as some class contained in a library?
- What if you named a function the same as some function contained in a library?
- This would result in what's referred to as a name clash
- The feature called namespaces solves this problem
Usage
- A namespace groups different identifiers (names) in a named scope
- The defined names will not conflict with other names defined elsewhere
Example 1#include <iostream>
using namespace std;
// Groups different identifiers under named space
namespace testlibrary
{
class Test;
void print();
}// Associate class with namespace
class testlibrary::Test
{
public:
Test();
};testlibrary::Test::Test()
{
cout << "Test object" << endl;
}// Associate function with namespace
void testlibrary::print()
{
cout << "Hello world" << endl;
}int main()
{
// Explicit use of namespace identifiers
testlibrary::Test t;
testlibrary::print();
return 0;
}OR
// using declarations
using testlibrary::Test;
using testlibrary::print;
int main()
{
Test t;
print();
return 0;
}OR
// using directive
// makes all names of given namespace available
using namespace testlibrary;int main()
{
Test t;
print();
return 0;
}Output
Test object
Hello world
Example 2
#include <iostream>
using namespace std;
namespace ns1
{
void print();
}namespace ns2
{
void print();
}void ns1::print()
{
cout << "Print from namespace ns1" << endl;
}void ns2::print()
{
cout << "Print from namespace ns2" << endl;
}using ns2::print;
int main()
{
print();
return 0;
}
Output
Print from namespace ns2
C++ standard library namespace
- C++ standard library contains many named components
- Components are grouped under one namespace called std
- When using identifiers from the C++ standard library, one can...1) Qualify identifier directly
#include <iostream>
int main()
{
std::cout << "hello world" << std::endl;
return 0;
}2) Provide a using declaration
#include <iostream>
using std::cout;
using std::endl;
int main()
{
cout << "hello world" << endl;
return 0;
}3) Provide a using directive
#include <iostream>
using namespace std;
int main()
{
cout << "hello world" << endl;
return 0;
}Header Files
- Several extensions were being used before the standard (.h, .hpp, .hxx, .H)
- Standard defined headers as no longer requiring extensions in include statements
- Only defined from the point of view of program, not operating system
- Note this requirement for no extension applies only to standard header files
- Still required for the programmer's header files#include <iostream>
#include <string>Other general concepts
Allocators
- Special objects to handle the allocation and deallocation of memory
- Different memory models (shared memory, garbage collection, ...)
- Interface to different memory models remains the same
Standard Template Library (STL)
- Subcomponent of the standard library
- Influenced the overall architecture of the standard library
- Standardization of common elements used by programmers
- Provides solutions to managing collections of data with modern/efficient algorithms
- Programmers benefit from innovations in area of data structures and algorithms
- Programmers don't necessarily have to know how they work
- New level of abstraction for the C++ programmer
- All components of the STL are templates - can work with any user type
- Usage avoids interoperatability problems among programmers
- Sets up a generic and common style of programming
- Avoids "reinventing the wheel"
- STL components include...Containers
- different methods of managing collections of objectsIterators
- used to step through elements of collections of objectsAlgorithms
- used to process the elements of collections
- search, sort, modify
- Forget programming your own linked lists, stacks, trees, search algorithms!
- STL is very large, we'll look at a few of the common components
Containers
- Template classes to manage a collection of elements
- Different types of containers meet different programmatic needsSequence containers
- Collection of elements ordered by position in the list (place of insertion)
- Position in list is independent of the value of the element
- vector, list, dequeAssociative containers
- Collection of elements ordered and sorted by value of the element
- Order is independent of the position in the list (place of insertion)
- set, multiset, map, multimap
Vector Sequence Container
- Manages elements in a dynamic array (size not known until run-time)
- Can add and remove elements from end (back) quickly
- Insertion in middle and front requires more time - all elements need to be moved
- Can randomly access elements directlyExample
#include <iostream>
#include <vector>using namespace std;
int main()
{
int i; // loop counter
vector<int> iv; // vector container of integers// Load container elements with values
for( i = 10; i < 16; ++i )
iv.push_back( i );
// Print container elements
for( i = 0; i < iv.size(); ++i )
cout << "iv[" << i << "]: " << iv[i] << endl;
return 0;
}Output
iv[0]: 10
iv[1]: 11
iv[2]: 12
iv[3]: 13
iv[4]: 14
iv[5]: 15
- Memory allocation of container elements handled by vector class
- Created, initially, as an empty container (no elements)
- Note method to append (push) elements to end (back) of container
- Same method used in all sequence container classes
- Note size method returns number of elements in container
- Note indexing of elements (random access) with subscript operator
Deque Sequence Container
- Pronounced "deck", designed as a "double-ended queue"
- Manages elements in a dynamic array (size not known until run-time)
- Can add and remove elements from both ends (front, back) quickly
- Insertion in middle requires more time - all elements need to be moved
- Can randomly access elements directlyExample
#include <iostream>
#include <deque>using namespace std;
int main()
{
int i;
deque<int> id; // deque container of integers// Load container elements with values at front
for( i = 10; i < 16; ++i )
id.push_front( i );// Load container elements with values at end
for( i = 20; i < 26; ++i )
id.push_back( i );
// Print container elements
for( i = 0; i < id.size(); ++i )
cout << "id[" << i << "]: " << id[i] << endl;
return 0;
}Output
id[0]: 15
id[1]: 14
id[2]: 13
id[3]: 12
id[4]: 11
id[5]: 10
id[6]: 20
id[7]: 21
id[8]: 22
id[9]: 23
id[10]: 24
id[11]: 25
- Memory allocation of container elements handled by deque class
- Created, initially, as an empty container (no elements)
- Method to append (push) elements to front of container (not provided in vector)
- Note method to append (push) elements to end of container
- Note size method returns number of elements in container
- Note indexing of elements with subscript operator
List Sequence Container
- Designed as a doubly linked list of elements
- Each element in list can refer to previous element and next element in list
- Manages elements in a dynamic array (size not known until run-time)
- Can add and remove elements anywhere (front, middle, back) quickly
- Cannot randomly access elements directly (must navigate through the chain)
Example
#include <iostream>
#include <list>using namespace std;
int main()
{
int i,j;
list<int> il; // linked list container of integers// Load container elements with values at front
for( i = 10; i < 16; ++i )
il.push_front( i );// Load container elements with values at end
for( i = 20; i < 26; ++i )
il.push_back( i );
// Print container elements
while( !il.empty() )
{
cout << il.front() << endl;
il.pop_front();
}
return 0;
}Output
15
14
13
12
11
10
20
21
22
23
24
25
- Memory allocation of container elements handled by list class
- Created, initially, as an empty container (no elements)
- Method to append (push) elements to front of container
- Note method to append (push) elements to end of container
- Note empty() method returns false if no elements in container
- Note front() method returns first element in the list
- Note pop_front() method removes first element in the list
Iterators
- Class objects that can "iterate" or navigate over elements
- Similar to pointers, iterators "point to" elements in the list
- Typically the elements are part of another STL container
- Iterators represent positions of elements within a list
- Iterators return elements at certain positions in a list
- Each container class defines its own iterator type as a nested class
- Container classes define member methods to use the iterators for access
- Example methods include:begin()
- Returns an iterator that represents the beginning of the elements in the listend()
- Returns an iterator that represents the position behind the last element
- Can only be used in an equality or comparison to test end of list++ operator
- Operator to step to the next element "pointed" to by the iterator* operator
- Operator to return the element "pointed" to by the iterator- Each container defines two types of iterators:
container type::iterator
- can iterate, access, and change the elements referenced by the iteratorcontainer type::const_iterator
- can only iterate and access the elements referenced by the iteratorExample
#include <iostream>
#include <list>using namespace std;
int main()
{
int i,j;
list<int> il; // linked list container of integers// Load container elements with values at front
for( i = 10; i < 16; ++i )
il.push_front( i );
// Declare the iterator
list<int>::const_iterator pos;// Assign the iterator to beginning of list;
// step through the list with the iterator
// print the element referenced by the iterator
for( pos = il.begin(); pos != il.end(); ++pos )
cout << *pos << endl;
return 0;
}
More on Containers
- All containers have several common operations implemented as methods
- Some of these common methods include:size()
- Returns the actual number of elements in the containerempty()
- Returns whether the container is empty or notswap()
- Swaps data with another containerinsert()
- Inserts elements into the containererase()
- Removes elements from the containerclear()
- Removes all elements making it empty- Some containers add their own specific methods to the common set
- The list container, for example, adds the following types of methods:splice()
- Inserts elements from one container into anothersort()
- Sorts elements in the listunique()
- Removes duplicate elements in the list
Algorithms
- Standard algorithms for processing elements of a collection
- Algorithms are NOT member functions of container classes
- Implemented as global functions that operate on iterators
- Types of algorithms include searching, sorting, copying, reordering
- Include header file <algorithm>
Using the STL
- STL programmers use containers, iterators, and algorithms together
- Containers contain iterators, algorithms operate on iterators...
Example
#include <iostream>
#include <list>
#include <algorithm>using namespace std;
void printList( const list<int> &l )
{
list<int>::const_iterator pos;
cout << "List:" << endl;
for( pos = l.begin(); pos != l.end(); ++pos )
cout << *pos << endl;
}int main()
{
int i;
list<int> il; // linked list container of integers// Load container elements with values at front
for( i = 10; i < 16; ++i )
il.push_front( i );
printList( il );// Sort the list (using list member method)
il.sort();
printList( il );// Use STL algorithm find to find an element with
// value 12 and return an iterator to this position
list<int>::iterator fpos;
fpos = find( il.begin(), il.end(), 12 );// Insert an element at the position found
il.insert( fpos, 101 );
printList( il );// Reverse order of the list using STL algorithm
reverse( il.begin(), il.end() );
printList( il );
return 0;
}
Output
List:
15
14
13
12
11
10
List:
10
11
12
13
14
15
List:
10
11
101
12
13
14
15
List:
15
14
13
12
101
11
10
- We can also use the STL with our own classes
- We can use an STL linked list without worrying about a next pointer!
Example
#include <iostream>
#include <list>using namespace std;
class Test
{
friend ostream &operator<<( ostream &strm, const Test &t )
{
strm << "Test:" << endl;
strm << " val: " << t.val << endl;
return strm;
}private:
int val;public:
Test( int v=0.0 ) { val = v; }};
int main()
{
int i;
list<Test> tl;// Load container elements with values at front
for( i = 10; i < 16; ++i )
tl.push_front( Test(i) );// Print container elements
list<Test>::const_iterator pos;
for( pos = tl.begin(); pos != tl.end(); ++pos )
cout << *pos << endl;
return 0;
}
Output
Test:
val: 15Test:
val: 14Test:
val: 13Test:
val: 12Test:
val: 11Test:
val: 10
Readings
Deitel & Deitel, Fourth Edition: 21.1, 22.4
| Back to Csc 125 Programming in C++ |
| Scott Badman Office: B132 Phone: 353-2250 sbadman@parkland.edu |
Parkland College, 2400 W. Bradley Avenue, Champaign, IL 61821 |