STL) Is a Collection of Containers and Algorithms Which Is Part of the Standard C++ Library
Total Page:16
File Type:pdf, Size:1020Kb
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 be? 2 Introduction to Systems Programming 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 3 Introduction to Systems Programming 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 4 Introduction to Systems Programming 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 5 Introduction to Systems Programming 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 6 Introduction to Systems Programming 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 7 Introduction to Systems Programming The STL includes several generic containers: Sequence Containers Associative Containers vector set deque map array multiset list multimap forward_list Unordered Associative Containers Adaptors unordered_set stack unordered_map queue unordered_multiset priority_queue unordered_multimap 8 Introduction to Systems Programming 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 void read_and_print() { vector<int> numbers; int input; while (cin >> input) { numbers.push_back(input); } for (int n : numbers) { cout << n << " "; } } 9 Introduction to Systems Programming Vector has a large selection of constructors, some of which are: 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()); 10 Introduction to Systems Programming 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 of operator[], which throws an exception if the index is illegal 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; } 11 Introduction to Systems Programming Elements can be efficiently inserted and removed from the end of a vector vector<string> words = { "Hello", "World" }; words.push_back("!!!"); words.pop_back(); Elements can also be inserted and erased from any place in the vector, though inefficiently vector<string> words = { "Hello", "World" }; vector<string>::iterator i = words.begin(); words.insert(++i, "Lovely"); words.erase(words.begin()); 12 Introduction to Systems Programming 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 13 Introduction to Systems Programming 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 14 Introduction to Systems Programming 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 deque<string> words = { "Hello", "World" }; words.pop_front(); words.push_front("Hi"); The container std::array is a constant-size array Size must be known at compilation time Basically wraps a C-style array array<string, 2> words = { "Hello", "World" }; words.at(0) = "Hi"; cout << words.at(3) << endl; 15 Introduction to Systems Programming 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 list<string> words = { "Hello", "World" }; list<string> words2 = { "Lovely" }; words.splice(++words.begin(), words2); 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 forward_list<string> words = { "Hello", "World" }; forward_list<string> words2 = { "Lovely" }; words.splice_after(words.begin(), words2); 16 Introduction to Systems Programming 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 set<int> numbers; for (int n : { 1, 3, 2, 3 }) { numbers.insert(n); } for (int n : numbers) { cout << n << endl; } 17 Introduction to Systems Programming Set stores its elements in sorted order By default, set compares elements using operator<() This is usually bad when using pointers class Employee { set<Employee*> employees; string name; public: employees.insert(new Employee("John")); Employee(string name) employees.insert(new Employee("Jill")); : name(name) {} employees.insert(new Employee("John")); string getName() const { return name; for (const Employee* e : employees) { } cout << e->getName() << endl; // ... } }; 18 Introduction to Systems Programming The comparison function is passed to set as a template argument We can replace the default operator<() with a function object class CompareByName { public: bool operator()(const Employee* e1, const Employee* e2) const { return e1->getName() < e2->getName(); } }; class Employee { set<Employee*, CompareByName> employees; string name; public: employees.insert(new Employee("John")); Employee(string name) employees.insert(new Employee("Jill")); : name(name) {} employees.insert(new Employee("John")); string getName() const { return name; for (const Employee* e : employees) { } cout << e->getName() << endl; // ... } }; 19 Introduction to Systems Programming 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 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; } 20 Introduction to Systems Programming 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; } 21 Introduction to Systems Programming 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 22 Introduction to Systems Programming 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 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(); } 23 Introduction to Systems Programming int main() { int main() { int main() { queue<int> numbers; stack<int> numbers; priority_queue<int>