Download presentation
Presentation is loading. Please wait.
Published byἸάκωβος Κυπραίος Modified over 6 years ago
1
10 – Iterators C++ Templates 4.6 The Iterator pgs. 264-271
Lab 03 - Iterator Strings Are Really Templates Refactoring Friends 10 – Iterators
2
Tip #10: Strings vs Character Arrays
Iterators Character arrays Size allocated statically. More memory cannot be allocated at run time. Unused allocated memory is wasted. Strings Size allocated dynamically. Memory allocated at run time on demand. Memory is pre-allocated, no memory is wasted. Threat of array decay (loss of type and dimensions when passing an array into function by value or pointer). As strings are represented as objects, no array decay occurs. String class functions: Input functions (3), Capacity functions (3), Iterator functions (4), Manipulating functions (2) No inbuilt functions to manipulate strings. (string.h library w/strcpy, strcat, strlen, strcmp, …) Implementations are fast. Implementation are non- standard and SLOW.
3
Lab 03 - Iterator
4
Array Container Access
Iterators By Index #include <iostream> using namespace std; int main() { int dog[] = { 1, 2, 3, 4 }; int* dptr = dog; for (size_t i = 0; i < 4; ++i) cout << *dptr++ << endl; } return 0; By Pointer #include <iostream> using namespace std; int main() { int dog[] = { 1, 2, 3, 4 }; for (size_t i = 0; i < 4; ++i) cout << dog[i] << endl; } return 0;
5
The "Old" Approach #include <iostream> #include <vector>
Iterators #include <iostream> #include <vector> using namespace std; int main() { vector<int> myArray; myArray.push_back(1); myArray.push_back(2); myArray.push_back(3); myArray.push_back(4); size_t y = 0; while (y != myArray.size()) cout << myArray[y] << " "; ++y; } return 0; #include <iostream> #include <list> using namespace std; int main() { list<int> myArray; myArray.push_back(1); myArray.push_back(2); myArray.push_back(3); myArray.push_back(4); size_t y = 0; while (y != myArray.size()) cout << myArray[y] << " "; ++y; } return 0;
6
The STL Iterator Approach
Iterators #include <iostream> #include <vector> using namespace std; int main() { vector<int> myArray; myArray.push_back(1); myArray.push_back(2); myArray.push_back(3); myArray.push_back(4); vector<int>::iterator iter = myArray.begin(); while (iter != myArray.end()) cout << *iter << " "; ++iter; } return 0; #include <iostream> #include <list> using namespace std; int main() { list<int> myArray; myArray.push_back(1); myArray.push_back(2); myArray.push_back(3); myArray.push_back(4); list<int>::iterator iter = myArray.begin(); while (iter != myArray.end()) cout << *iter << " "; ++iter; } return 0;
7
Why Use an Iterator? When avoiding iterators:
Assumes your container has index ([]), at, and increment (++,--)operators. Assumes container elements can be randomly accessed, are contiguous, and same size (true for vector but not for many other containers.) Requires many versions of common algorithms (ie., sort, reverse, etc.) Iterators bring you closer to container independence. You're not making assumptions about random-access ability, storage format, or efficiency of operations such as size(). You only need to know that the container has iterator capabilities. Iterators enhance your code further with standard algorithms. Depending on what it is you're trying to achieve, you may elect to use std::for_each(), std::transform(), std::sort() and so on. By using a standard algorithm rather than an explicit loop you're avoiding re-inventing the wheel. Your code is likely to be more efficient (given the right algorithm is chosen), correct and reusable.
8
Iterator Lab Iterators The concept of an iterator is fundamental to understanding the C++ Standard Template Library (STL). Iterators provide access to data stored in container classes (e.g. vector, map, list, etc.) Your Iterator lab implements a C++ array container class that uses an iterator to access the array elements. Your container supplies begin() and end() functions. Your iterator object overloads the not equal ("!="), dereference ("*"), and pre-increment ("++") operators. Use an iterator to sequentially access elements of the associated array class. Read integer values from a file into the array class. Instantiate an iterator using the begin() function and then use the iterator to iterate thru the array values until the iterator equals the iterator returned by the end() function.
9
Nested Class MyArray Iterator Iterators template<typename T>
{ private: // MyArray data public: MyArray(const size_t maxSize) { ... } void push_back(T item) { ... } std::string toString() const { ... } friend std::ostream& operator<< (std::ostream& os, const MyArray<T>& myArray) {}; }; MyArray Iterator class Iterator { private: // Iterator data and private functions public: Iterator(T* array, size_t size, size_t index) { ... } bool operator!= (const Iterator& other) const { ... } // not-equal Iterator& operator++ () { ... } // pre-increment ++ T& operator*() const { ... } // dereference std::string toString() const { ... } friend std::ostream& operator<< (std::ostream& os, const Iterator& iter) {} }; Iterator begin() { ... } // pointer to first element Iterator end() { ... } // pointer AFTER last element
10
main Open I/O Streams Read / push_back integer into numbers container.
Iterators int main(int argc, char * argv[]) { VS_MEM_CHECK; MyArray<int> numbers(MAX_ARRAY_SIZE); ifstream in(argv[1]); std::ostream& out = (argc < 3) ? std::cout : *(new std::ofstream(argv[2]); out << endl << endl; int i; while (in >> i) numbers.push_back(i); out << numbers << endl << endl; out << "SEQUENTIAL" << endl; MyArray<int>::Iterator iter = numbers.begin(); out << "iter: " << iter << endl; for (; iter != numbers.end(); ++iter) out << *iter << " "; return 0; } Open I/O Streams Read / push_back integer into numbers container. Instantiate Iterator Use friend insertion operator to examine Iterator Output number's contents using dereferencing operator Loop until iter and numbers.end() are equal
11
Output of Iterator Lab myArray 1 2 3 4 5 6 7 8 9 10
Iterators myArray SEQUENTIAL iter1: size=20 PRIME (Bonus) COMPOSITE (Bonus) FIBONACCI (Bonus) iter2: size=20 3=1+2
12
You may freely use the code in any way you deem useful.
****Disclaimer**** The following code examples are flawed and incomplete, but demonstrate how an iterator class might be implemented. You may freely use the code in any way you deem useful.
13
Step 1 – int Array Class Iterators #include <iostream> #include <string> #include <sstream> #define MAX_ARRAY_SIZE using namespace std; class MyArray { private: size_t size_; int* array_; public: MyArray(size_t maxSize) : size_(0) { array_ = (int*)malloc(maxSize * sizeof(int)); } void push_back(int item) { array_[size_++] = item; } }; int main(int argc, char * argv[]) { MyArray numbers(MAX_ARRAY_SIZE); numbers.push_back(1); numbers.push_back(2); numbers.push_back(3); numbers.push_back(4); cout << numbers << endl; return 0; } Be sure to use a destructor to free array! string toString() const { stringstream out; out << "myArray"; for (size_t i = 0; i < size_; ++i) out << ((i % 10) ? " " : "\n") << array_[i]; return out.str(); } friend std::ostream& operator<< (ostream& os, const MyArray<T>& myArray) os << myArray.toString(); return os; Remember, every class needs a toString and a Friend!
14
Step 2 – Template Class Iterators #include <iostream> #include <string> #include <sstream> #define MAX_ARRAY_SIZE using namespace std; template<typename T> class MyArray { private: size_t size_; T* array_; public: MyArray(size_t maxSize) : size_(0) { array_ = (T*)malloc(maxSize * sizeof(T)); } void push_back(T item) { array_[size_++] = item; } }; int main(int argc, char * argv[]) { MyArray<int> numbers(MAX_ARRAY_SIZE); numbers.push_back(1); numbers.push_back(2); numbers.push_back(3); numbers.push_back(4); cout << numbers << endl; return 0; } Templates are a feature of the C++ programming language that allows functions and classes to operate with generic types, allowing a function or class to work on many different data types without being rewritten for each one. There are three kinds of templates: function templates, class templates and, since C++14, variable templates.
15
Step 3 – Add a Nested Iterator
Iterators #include <iostream> #include <string> #include <sstream> #define MAX_ARRAY_SIZE using namespace std; template<typename T> class MyArray { private: size_t size_; T* array_; public: MyArray(size_t maxSize) : size_(0) { array_ = (T*)malloc(maxSize * sizeof(T)); } void push_back(T item) { array_[size_++] = item; } class Iterator size_t index_; Iterator(T* a, size_t s) : array_(a), index_(s) { ... } T& operator[](size_t i) const { return array_[i]; } }; Iterator begin() { return MyArray<T>::Iterator(array_, 0); } Iterator end() { return MyArray<T>::Iterator(array_, size_); } int main(int argc, char * argv[]) { MyArray<int> numbers(MAX_ARRAY_SIZE); numbers.push_back(1); numbers.push_back(2); numbers.push_back(3); numbers.push_back(4); MyArray<int>::Iterator iter = numbers.begin(); for (size_t i = 0; i < 4; ++i) cout << iter[i] << ' '; cout << endl << endl; return 0; } MyArray Iterator Nested classes can access all members of the parent via a reference/pointer.
16
Step 4 – Add Functionality
Iterators #include <iostream> #include <string> #include <sstream> #define MAX_ARRAY_SIZE using namespace std; template<typename T> class MyArray { private: size_t size_; T* array_; public: MyArray(size_t maxSize) : size_(0) { array_ = (T*)malloc(maxSize * sizeof(T)); } void push_back(T item) { array_[size_++] = item; } class Iterator size_t index_; Iterator(T* a, size_t s) : array_(a), index_(s) { ... } T& operator[](size_t i) const { return array_[index_]; } T& operator*() const { ... } Iterator& operator++() { ... } }; Iterator begin() { return MyArray<T>::Iterator(array_, 0); } Iterator end() { return MyArray<T>::Iterator(array_, size_); } int main(int argc, char * argv[]) { MyArray<int> numbers(MAX_ARRAY_SIZE); numbers.push_back(1); numbers.push_back(2); numbers.push_back(3); numbers.push_back(4); MyArray<int>::Iterator iter = numbers.begin(); for (size_t i = 0; i < 4; ++i, ++iter) cout << *iter << ' ‘; cout << endl << endl; return 0; } Add dereference (*) and pre-increment (++) operators.
17
Requirements Iterators Points Requirement (35 + 10 Points) 5
argv[1] and argv[2] used for input / output streams respectively. No execution user interaction (i.e. system("pause"); or getchr();). A template array class contains unsorted integer numbers. Numbers are added to the container using a push_back member function. The array class contains a nested iterator class. The array class member functions begin() and end() instantiate and return iterator objects; the begin iterator points to the 1st element and the end iterator points after the last element. The iterator class correctly overloads the dereferencing ("*"), pre-incrementing ("++"), and not equal ("!=") function operators. All classes (including the iterator) have public toString and friend insertion member functions. The insertion operator function is used to send the contents of the array container and iterators to the output stream. The array class content from all input files is correctly output using an iterator. BONUS: Add a size() function and index function operator ("[]") to your array class. Use these functions to output the prime and composite array class elements. BONUS: Add a post-increment function operator ("++") to your nested iterator class. Use the dereference and post-increment operators (indirect auto-increment *iter++) to output all Fibonacci-like array class elements. VS_MEM_CHECK macro is included in main to detect memory leaks. No Memory leaks are reported.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.