文章目录
- 1、自定义String实现iterator
- 2、自定义vector实现iterator
- 3、迭代器失效问题
迭代器的功能:提供一种统一的方式,来透明的遍历容器。
迭代器可以透明的访问容器内部的元素的值,而无需了解其底层遍历机制具体是数组的下标还是链表的指针等等。
泛型算法参数接收的都是迭代器!
泛型算法 - 全局的函数 - 给所有容器用的
泛型算法,有一套方式,能够统一的遍历所有的容器的元素 - 迭代器
1、自定义String实现iterator
#include <iostream>
#pragma warning(disable:4996)using namespace std;class String {
public:String(const char *p = nullptr) {if (p != nullptr) {_pstr = new char[strlen(p) + 1];strcpy(_pstr, p);}else {_pstr = new char[1];_pstr[0] = '\0';}}~String() {delete[] _pstr;_pstr = nullptr;}String(const String &str) {_pstr = new char[strlen(str._pstr) + 1];strcpy(_pstr, str._pstr);}String &operator=(const String &str) {if (this == &str) return *this;delete[] _pstr;_pstr = new char[strlen(str._pstr) + 1];strcpy(_pstr, str._pstr);return *this;}bool operator>(const String &str) const {return strcmp(_pstr, str._pstr) > 0;}bool operator<(const String &str) const {return strcmp(_pstr, str._pstr) < 0;}bool operator==(const String &str) const {return strcmp(_pstr, str._pstr) == 0;}int length() const { return strlen(_pstr); }const char *c_str() const { return _pstr; }//char ch=str6[6]; str6[6]='7'char &operator[](int index) { return _pstr[index]; }//char ch=str6[6]; 不允许修改! str6[6]='7'const char &operator[](int index) const { return _pstr[index]; }// 给string字符串类型提供迭代器的实现class iterator {public:iterator(char *p = nullptr) : _p(p){}bool operator!=(const iterator &it) {return _p != it._p;}void operator++() {++_p;}char &operator*() {return *_p;}private:char *_p;};// begin返回的是容器底层首元素的迭代器的表示iterator begin() { return iterator(_pstr); }// end返回的是容器末尾元素后继位置的迭代器的表示iterator end() { return iterator(_pstr + length()); }private:char *_pstr;friend String operator+(const String &lhs, const String &rhs);friend ostream &operator<<(ostream &out, const String &str);
};String operator+(const String &lhs, const String &rhs) {//char *ptmp = new char[strlen(lhs._pstr) + strlen(rhs._pstr) + 1];//strcpy(ptmp, lhs._pstr);//strcat(ptmp, rhs._pstr);//return String(ptmp); // 内存泄漏:ptmp 未释放//char *ptmp = new char[strlen(lhs._pstr) + strlen(rhs._pstr) + 1];//strcpy(ptmp, lhs._pstr);//strcat(ptmp, rhs._pstr);//String tmp(ptmp); // 效率太低//delete[] ptmp; //return tmp;String result;delete[] result._pstr; // 释放默认构造的空字符串内存result._pstr = new char[strlen(lhs._pstr) + strlen(rhs._pstr) + 1];strcpy(result._pstr, lhs._pstr);strcat(result._pstr, rhs._pstr);return result;
}ostream &operator<<(ostream &out, const String &str) {out << str._pstr;return out;
}int main() {String str1 = "hello world!";// 容器的迭代器类型String::iterator it = str1.begin();for (; it != str1.end(); ++it) {cout << *it << " ";}cout << endl;// C++11 foreach的方式来遍历容器的内部元素的值 => 底层,还是通过迭代器进行for (auto s : str1) {cout << s << " ";}cout << endl;return 0;
}
2、自定义vector实现iterator
#include <iostream>
using namespace std;template<typename T>
class vector {
public:vector(int size = 10) {_first = new T[size];_last = _first;_end = _first + size;}~vector() {delete[]_first;_first = _last = _end = nullptr;}vector(const vector<T> &rhs) {int size = rhs._end - rhs - _first;_first = new T[size];int len = rhs._last - rhs._first;for (int i = 0; i < len; ++i) {_first[i] = rhs._first[i];}_last = _first + len;_end = _first + size;}vector<T> &operator=(const vector<T> &rhs) {if (this == &rhs) {return *this;}delete[]_first;int size = rhs._end - rhs - _first;_first = new T[size];int len = rhs._last - rhs._first;for (int i = 0; i < len; ++i) {_first[i] = rhs._first[i];}_last = _first + len;_end = _first + size;return *this;}void push_back(const T &val) {if (full()) {expand();}*_last++ = val;}void pop_back() {if (empty()) {return;}--_last;}T back() {// 返回容器末尾元素的值return *(_last - 1);}bool full() const { return _last == _end; }bool empty() const { return _last == _first; }int size() const { return _end - _first; }T &operator[](int index) { // vec[2]if (index < 0 || index >= size()) {throw "OutOfRangeException";}return _first[index];}//迭代器一般实现成容器的嵌套类型class iterator {public:iterator(T *ptr = nullptr) : _ptr(ptr){}bool operator!=(const iterator &it) const {return _ptr != it._ptr;}void operator++() {_ptr++;}T &operator*() {return *_ptr;}private:T *_ptr;};// 需要给容器提供begin和end方法iterator begin() { return iterator(_first); }iterator end() { return iterator(_last); }private:T *_first; // 指向数组空间的起始位置T *_last;// 指向数组中有效元素的后继位置T *_end;// 指向数组空间的后继位置void expand() {int size = _end - _first;T *ptmp = new T[size * 2];for (int i = 0; i < size; ++i) {ptmp[i] = _first[i];}delete[] _first;_first = ptmp;_last = _first + size;_end = _last + size;}
};class Test {
public:Test() { cout << "Test()" << endl; }~Test() { cout << "~Test()" << endl; }
};int main() {vector<int> vec;for (int i = 0; i < 20; ++i) {vec.push_back(rand() % 100);}for (int i = 0; i < vec.size(); ++i) {cout << vec[i] << " ";}cout << endl;//vector<int>::iterator it = vec.begin();auto it = vec.begin();for (; it != vec.end(); ++it) {cout << *it << " ";}cout << endl;for (auto v : vec) {cout << v << " ";}cout << endl;return 0;
}
3、迭代器失效问题
问题引入
vector<int> vec;for (int i = 0; i < 20; ++i) {vec.push_back(rand() % 100);}// 把vec容器中所有的偶数全部删除auto it = vec.begin();for (; it != vec.end(); ++it) {if (*it % 2 == 0) {//迭代器失效的问题,第一次调用erase以后,迭代器it就失效了vec.erase(it); // insert(it,val) erase(it)break;}}//给vec容器中所有的偶数前面添加一个小于偶数值1的数字auto it= vec.begin();for (; it != vec.end(); ++it) {if (*it % 2 == 0) {// 这里的迭代器在第一次insert之后,iterator就失效了vec.insert(it, *it - 1);break;}}
迭代器为什么会失效?
a. 当容器调用erase方法后,当前位置到容器末尾元素的所有的迭代器全部失效了。
b. 当容器调用insert方法后,当前位置到容器末尾元素的所有的迭代器全部失效了。
首元素-> 插入点/删除点:迭代器依然有效
插入点/删除点->末尾元素:迭代器全部失效
c. insert来说,如果引起容器内存扩容。
首元素-> 插入点/删除点 ->末尾元素:原来容器的所有的迭代器就全部失效了
迭代器失效了以后,问题该怎么解决?
对插入/删除点的迭代器进行更新操作。
vector<int> vec;for (int i = 0; i < 20; ++i) {vec.push_back(rand() % 100);}for (auto v : vec) {cout << v << " ";}cout << endl;// 把vec容器中所有的偶数全部删除auto it = vec.begin();while (it != vec.end()) {if (*it % 2 == 0) {//迭代器失效的问题,第一次调用erase以后,迭代器it就失效了it = vec.erase(it); // insert(it,val) erase(it)}else {++it;}}for (auto v : vec) {cout << v << " ";}cout << endl;//给vec容器中所有的偶数前面添加一个小于偶数值1的数字auto it = vec.begin();for (; it != vec.end(); ++it) {if (*it % 2 == 0) {// 这里的迭代器在第-次insert之后,iterator就失效了it = vec.insert(it, *it - 1);//break;++it;}} for (auto v : vec) {cout << v << " ";}cout << endl;