and more... The standard library is the collection of functions and - - PowerPoint PPT Presentation
and more... The standard library is the collection of functions and - - PowerPoint PPT Presentation
Containers, algorithms and more... The standard library is the collection of functions and types that is supplied with every standard-compliant C++ compiler What should be in the standard library? And equally important: what should not
The standard library is the collection of
functions and types that is supplied with every standard-compliant C++ compiler
What should be in the standard library?
And equally important: what should not be?
Introduction to Systems Programming 2
The standard library should:
Provide basic functionality which the user can
have difficulty implementing himself:
Memory management Input / output Implementation-dependent information
Save and simplify work:
Supply useful non-primitive facilities
Introduction to Systems Programming 3
The standard library cannot contain problem-
specific code
For example – a Student class
It should contain generic classes and functions
which are usable in a variety of problems:
Containers – such as list, set, etc. Algorithms – such as sorting, searching Popular classes – such as string
Introduction to Systems Programming 4
What are the requirements from the standard library's
containers and algorithms?
Simple to use
Interfaces should be uniform and convenient
Complete
Reasonable features should be included
Efficient
Library code might take a large part of the execution time
Extensible
The user should be able to add new containers and algorithms that work with the given ones
Introduction to Systems Programming 5
The containers included in the standard library should
be generic
We have seen several ways to implement generic
containers:
Using void* and pointers to functions Using templates Using subtyping and polymorphism
Introduction to Systems Programming 6
The standard template library (STL) is a collection of
containers and algorithms which is part of the standard C++ library
Makes heavy use of C++ templates
And many interesting and advanced programming
techniques
Developed by Alexander Stepanov and Meng Lee at HP
Introduction to Systems Programming 7
The STL includes several generic containers:
Introduction to Systems Programming 8
vector deque array list forward_list Sequence Containers stack queue priority_queue Adaptors set map multiset multimap Associative Containers unordered_set unordered_map unordered_multiset unordered_multimap Unordered Associative Containers
The most commonly used container is std::vector
Defined in the standard header <vector>
Essentially, a vector is a dynamic array
Elements are sequential in memory Fast random access to elements by index Insertion and removal of elements at the end of the vector is fast
Due to pre-allocation of memory
Insertion and removal elsewhere in the vector may be very slow
Introduction to Systems Programming 9
void read_and_print() { vector<int> numbers; int input; while (cin >> input) { numbers.push_back(input); } for (int n : numbers) { cout << n << " "; } }
Vector has a large selection of constructors,
some of which are:
Introduction to Systems Programming 10
vector<int> v1; vector<double> v2(10, 1.0); vector<double> v3(10); vector<double> v4(v2); vector<string> words = { "Hello", "World" }; int array[] = { 1, 2, 3 }; vector<int> v5(array, array + 3); vector<int> v6(v2.begin(), v2.end());
Vectors have random access like arrays:
operator[] can be used to access elements without any run-time
check of the index (result is undefined if the index is invalid!)
The member function at() provides a safer (but slower) version
- f operator[], which throws an exception if the index is illegal
Introduction to Systems Programming 11
vector<string> words = { "Hello", "World" }; for (unsigned i = 0; i < words.size(); ++i) { cout << words[i] << endl; } try { cout << words.at(2) << endl; } catch (const std::out_of_range& e) { cerr << e.what() << endl; }
Elements can be efficiently inserted and removed from the
end of a vector
Elements can also be inserted and erased from any place in
the vector, though inefficiently
Introduction to Systems Programming 12
vector<string> words = { "Hello", "World" }; vector<string>::iterator i = words.begin(); words.insert(++i, "Lovely"); words.erase(words.begin()); vector<string> words = { "Hello", "World" }; words.push_back("!!!"); words.pop_back();
Elements placed into a vector must be “copy
constructible” and “assignable”
So a working copy c’tor and operator= are required A default c’tor is not required
When dealing with a polymorphic base class, use
shared_ptr to store the elements in the vector
This will save you from the need to explicitly delete
elements before removing them from the vector
Introduction to Systems Programming 13
There is more to vector's interface – look online
This is true for all containers
Some things that were not discussed:
Vectors have methods to allow fine control over the memory
they use (e.g., resizing, preallocation)
Vectors, like other containers, have an optional template
argument called Allocator
Allocators allow the user to control how and where new elements are allocated – this is important for efficiency reasons We will ignore them in our survey of the STL
Introduction to Systems Programming 14
The rest of the containers behave similarly to vector
So no need to go over them thoroughly
The container std::deque (short for "Double Ended Queue") is like a vector, but allows fast insertion and removal from its beginning as well
Using the push_front() and pop_front() methods
The container std::array is a constant-size array
Size must be known at compilation time Basically wraps a C-style array
Introduction to Systems Programming 15
deque<string> words = { "Hello", "World" }; words.pop_front(); words.push_front("Hi"); array<string, 2> words = { "Hello", "World" }; words.at(0) = "Hi"; cout << words.at(3) << endl;
The container std::list is implemented as a doubly-linked list
There are no methods for random (index-based) access There is support for fast merging and splicing of lists
The container std::forward_list is a singly-linked list with pointers from each node only to the next one
Takes less memory But has a slimmer interface, e.g., no operator--() for iterators
Introduction to Systems Programming 16
list<string> words = { "Hello", "World" }; list<string> words2 = { "Lovely" }; words.splice(++words.begin(), words2); forward_list<string> words = { "Hello", "World" }; forward_list<string> words2 = { "Lovely" }; words.splice_after(words.begin(), words2);
Unlike sequence containers, associative containers
do not provide control over element order
The order of iteration is unrelated to the order of insertion
Example: set is an associative container
Introduction to Systems Programming 17
set<int> numbers; for (int n : { 1, 3, 2, 3 }) { numbers.insert(n); } for (int n : numbers) { cout << n << endl; }
Set stores its elements in sorted order
By default, set compares elements using operator<() This is usually bad when using pointers
Introduction to Systems Programming 18
set<Employee*> employees; employees.insert(new Employee("John")); employees.insert(new Employee("Jill")); employees.insert(new Employee("John")); for (const Employee* e : employees) { cout << e->getName() << endl; } class Employee { string name; public: Employee(string name) : name(name) {} string getName() const { return name; } // ... };
The comparison function is passed to set as a template argument
We can replace the default operator<() with a function object
Introduction to Systems Programming 19
set<Employee*, CompareByName> employees; employees.insert(new Employee("John")); employees.insert(new Employee("Jill")); employees.insert(new Employee("John")); for (const Employee* e : employees) { cout << e->getName() << endl; } class Employee { string name; public: Employee(string name) : name(name) {} string getName() const { return name; } // ... }; class CompareByName { public: bool operator()(const Employee* e1, const Employee* e2) const { return e1->getName() < e2->getName(); } };
Another associative container is map
A map stores pairs of (key, value) The keys are unique (only one of each) Map is basically a set, with extra information stored
for each element
Introduction to Systems Programming 20
map<int, string> idToName; idToName[123456789] = "John"; idToName[987654321] = "Jill"; idToName[123454321] = "John"; idToName[123454321] = "Jill"; for (const pair<int,string>& idNamePair : idToName) { cout << idNamePair.first << ": " << idNamePair.second << endl; }
void most_frequent_word() { string word; map<string, int> count; while (cin >> word) { count[word]++; } string max_word; int max_count = 0; for (const pair<string,int>& p : count) { if (p.second > max_count) { max_word = p.first; max_count = p.second; } } cout << max_word << endl; }
Introduction to Systems Programming 21
The STL supplies multiset and multimap which allow
storing the same key multiple times
In addition, C++11 adds unordered_set, unordered_map,
unordered_multiset and unordered_multimap
These containers use a hash-table implementation instead of a
binary tree
Introduction to Systems Programming 22
Adaptors are container wrappers which limit or modify the existing container's interface
For example, stack or queue Why would we want to limit an interface?
Adaptors take a container as an additional template argument
Allowing the user to choose the implementation of his
stack/queue/priority queue
They adapt the sequence container to a specific, simple usage
Introduction to Systems Programming 23
stack<int> stack1; stack<int, list<int>> stack2; for (int n : { 2, 1, 3 }) { stack1.push(n); } while (!stack1.empty()) { stack2.push(stack1.top()); stack1.pop(); }
Introduction to Systems Programming 24
int main() { stack<int> numbers; for (int n : { 2, 1, 3 }) { numbers.push(n); } while (!numbers.empty()) { cout << numbers.top(); cout << " "; numbers.pop(); } return 0; } int main() { queue<int> numbers; for (int n : { 2, 1, 3 }) { numbers.push(n); } while (!numbers.empty()) { cout << numbers.front(); cout << " "; numbers.pop(); } return 0; } int main() { priority_queue<int> numbers; for (int n : { 2, 1, 3 }) { numbers.push(n); } while (!numbers.empty()) { cout << numbers.top(); cout << " "; numbers.pop(); } return 0; }
Don’t feel confused by the large number of
different containers
If you don't know which to use, go with vector In time, the differences will become clearer
How each of these containers can be
implemented efficiently is taught in Data Structures 1 (234218)
Introduction to Systems Programming 25
A common feature of most containers is iterators This enables writing generic algorithms that work
with several containers
Introduction to Systems Programming 26
template<class InputIterator, class OutputIterator> OutputIterator copy(InputIterator first, InputIterator last, OutputIterator target) { while (first != last) *(target++) = *(first++); return target; } set<int> numbers; // ... vector<int> v(numbers.size()); copy(numbers.begin(), numbers.end(), v.begin());
Iterators are a concept – there is no class “iterator”
A concept is essentially a set of requirement imposed on a
template argument
Many classes can be iterators, as long as they support the
required operations
The STL recognizes five categories of iterators:
Introduction to Systems Programming 27
A forward iterator supports the following 3 operations:
Advancing the iterator with ++i and i++ Operator* for dereferencing (retrieving the current element) Comparison with == and !=
Introduction to Systems Programming 28
forward_list<int> numbers = { 1, 2, 3, 4 }; forward_list<int>::iterator i = numbers.begin(); while (i != numbers.end()) { *i = 2 * (*i); ++i; }
A bi-directional iterator adds support for decrementing
the iterator
Supports --i and i-- Supports all of the forward iterator's operations std::list provides bi-directional iterators
Introduction to Systems Programming 29
list<int> numbers = { 1, 2, 3, 4 }; list<int>::iterator i = numbers.end(); while (i != numbers.begin()) {
- -i;
cout << *i << endl; }
A random access iterator supports:
Anything that can be done with a bi-directional iterator Comparison through operators <, <=, > and >= Moving forward or backward by n elements in the container with + or - Calculating the distance between two iterators with - Random access using operator[]
A pointer is a random access iterator for a C-style array
std::vector provides a random access iterator
Introduction to Systems Programming 30
vector<int> numbers = { 1, 2, 3, 4, 5, 6, 7, 8 }; vector<int>::iterator i = numbers.begin(); while (i < numbers.end()) { cout << *i << endl; i += 3; }
An output iterator supports the same operations as a
forward iterator with one important difference:
The dereferenced element (via operator*) can only be
written to, and only once
The range of elements may only be iterated once
We can get such an iterator for an ostream object:
Introduction to Systems Programming 31
- stream_iterator<int> out (cout, ", ");
int n; while (cin >> n) { *(out++) = n; }
An input iterator is similar to an output iterator, but this
time the referenced element can only be read from
Again, you may only do a single pass on the range of elements
Introduction to Systems Programming 32
map<string, int> count; ifstream fin("words.txt"); istream_iterator<string> end; for (istream_iterator<string> i(fin); i != end; ++i) { count[*i]++; }
We can now use the different iterator categories to
describe the requirements of generic algorithms
Introduction to Systems Programming 33
template<class InputIterator, class OutputIterator> OutputIterator copy(InputIterator first, InputIterator last, OutputIterator target) { while (first != last) *(target++) = *(first++); return result; } ifstream fin("words.txt");
- fstream fout("output.txt");
copy(istream_iterator<string>(fin), istream_iterator<string>(),
- stream_iterator<string>(fout, " "));
The STL comes with the <algorithm> header which contains a variety of common algorithms
All these algorithms operate on iterators, not on specific containers Combining these algorithms with the containers gives a powerful
standard library
Users can create new containers and new algorithms that can be
combined with the STL by simply following the same conventions
Introduction to Systems Programming 34
bool is_anagram(string str1, string str2) { sort(str1.begin(), str1.end()); sort(str2.begin(), str2.end()); return str1 == str2; } cout << is_anagram("dog", "god"); cout << is_anagram("no", "way");
Count the number of words in a string:
Introduction to Systems Programming 35
int count_words(string str) { istringstream is(str); istream_iterator<string> start(is); istream_iterator<string> end; return std::distance(start, end); } string str("The quick brown fox jumps\n" " over the lazy dog"); cout << count_words(str) << endl;
Erase values from a vector according to a given
condition, and print its contents:
Introduction to Systems Programming 36
vector<double> numbers = { -1.0, 0.33, -0.44, 2.5 }; vector<double>::iterator i = remove_if(numbers.begin(), numbers.end(), is_negative); numbers.erase(i, numbers.end()); copy(numbers.begin(), numbers.end(), ostream_iterator<double>(cout, ", ")); bool is_negative(double d) {
return d < 0; }
The STL supplies a set of useful tools for programming in C++
Use it whenever possible instead of reinventing the wheel
Don’t expect to remember it by heart – it’s too big
Look online for resources, usually what you need already exists There's much more to it, but outside the scope of this course
There are many containers, but in many cases there is no
need to optimize anything:
If you don’t know what you need – use a vector
Introduction to Systems Programming 37
“The bearing of a child takes nine months, no matter how many women are assigned. Many software tasks have this characteristic because of the sequential nature of debugging.”
- Fred Brooks
Introduction to Systems Programming 38