vector的使用和模拟
目录vector的基本使用构造函数拷贝构造迭代器容器元素访问修改emplace_back和push_back区别结构化绑定迭代器失效vector的模拟迭代器容器元素访问元素修改构造、赋值和析构:总代码综合总结vector的基本使用构造函数templateclass Constain void Print(const Constain con) { for (auto e : con) { cout e ; } cout endl; } int main() { //以下三种都可以一般会忽略括号直接用花括号 //vectorint v1({ 1,2,3,4,5 }); vectorint v1{ 1,2,3,4,5 }; //vectorint v1 { 1,2,3,4,5 }; Print(v1); vectorint v2(20, 100); Print(v2); vectorint v3(v1.begin() 2, v1.end()); Print(v3); return 0; }运行结果以上是我觉得较为有用的初始化构造函数c98需要其他构造可以直接查阅文档vector::vector - C Reference拷贝构造vectorint v4 v1;//这里继承了上面的代码{12345} Print(v4);迭代器这里迭代器就不一一写了这里可以理解成像指针一样的东西进行遍历使用就好了如//可修改 void test02() { vectorint v1 {1,2,3,4,5}; vectorint::iterator it1 v1.begin(); while (it1 ! v1.end()) { cout *it1 ; it1; } } //只读 void test03() { vectorint v1 {1,2,3,4,5}; vectorint::const_iterator it1 v1.cbegin(); while (it1 ! v1.cend()) { cout *it1 ; it1; } } //反向迭代器 void test04() { vectorint v1 {1,2,3,4,5}; vectorint::reverse_iterator it1 v1.rbegin(); while (it1 ! v1.rend()) { cout *it1 ; it1; } }运行结果容器void test05() { vectorstring v1 { hellow,world,!!!!! }; cout 大小: v1.size() endl; cout 扩容前: v1.capacity() endl; cout v1.max_size() endl;//没实际意义扩容阔不了这么大 v1.resize(5, bear); Print(v1); cout resize扩容后: v1.capacity() endl; cout 判空: v1.empty() endl; v1.reserve(10); cout reserve扩容后: v1.capacity() endl; v1.shrink_to_fit(); cout shrink_to_fit缩容后: v1.capacity() endl; }元素访问void test06() { vectorstring v1 { hellow,world,!!!!! }; cout operator[]: v1[1] endl; cout at: v1.at(1) endl; cout front: v1.front() endl; cout back: v1.back() endl; cout data: v1.data() endl;//返回起始元素地址 }运行结果修改void test07() { vectorint v1{1,2,3,4,5}; v1.assign(20, 100);//替代原来的vector Print(v1); vectorint v2; v2.push_back(1); v2.push_back(2); v2.push_back(3); v2.push_back(4); v2.push_back(5); Print(v2); v2.pop_back(); cout pop_back后:; Print(v2); v2.insert(v2.begin()2, 100); cout insert插入后:; Print(v2); v2.erase(v2.begin() 1); cout erase删除后:; Print(v2); vectorint v3; v3.swap(v2); cout 交换后的v2:; Print(v2); cout 交换后的v3:; Print(v3); v3.clear(); cout clear的v3:; Print(v3); }emplace_back和push_back区别emplace_back和push_back构造一个临时对象然后将其拷贝或移动到容器中在初始化时在特殊场景下emplace_back效率会更高直接在容器内存中构造对象避免创建临时对象push_back和emplace_back在扩容过程中都会调用拷贝构造。void test08() { struct A { A(int a,int b,int c) :_a(a) ,_b(b) ,_c(c) { cout A() endl; } A(const A aa) { cout A(const A aa) endl; _a aa._a; _b aa._b; _c aa._c; } int _a 1; int _b 2; int _c 3; }; vectorint v1; //内置类型效率差不多 v1.push_back(1); v1.emplace_back(1); for (auto e : v1) { cout e ; } cout endl; cout endl; vectorA v2; //v2.reserve(10); //完整对象 A aa1(4, 5, 6); cout ******************************** endl; cout push_back完整实例化对象:endl; v2.push_back(aa1); v2.push_back(A(7,8,9));//匿名对象 cout push_back:传递构造参数不是完整实例化对象 endl; //需要调用构造再调用拷贝构造 v2.push_back({ 1,2,3 }); cout emplace_back完整实例化对象:endl;; //这里拷贝2次是因为第一个拷贝是因为扩容拷贝然后第二次是需要拷贝到vector中 v2.emplace_back(aa1); v2.emplace_back(A(7, 8, 9)); cout emplace_back:传递构造参数不是完整实例化对象 endl; //避免临时对象的产生直接调用构造效率较高 v2.emplace_back( 1,2,3 ); cout endl; cout endl; }这里很明显在传递构造参数时就会使得拷贝构造变少甚至不拷贝但是在其他方面如已初始化的反而会拷贝更多拷贝结构化绑定结构化绑定用于类型是自定义类型的类就是一个自定义类型有多个成员访问就好用和范围for一样只不过范围for不好写多个成员访问这里结构化绑定就是可以直接访问。可能发生拷贝构造可以用引用消除这个拷贝构造void test09() { struct A { A(int a, int b, int c) :_a(a) , _b(b) , _c(c) { cout A() endl; } A(const A aa) { cout A(const A aa) endl; _a aa._a; _b aa._b; _c aa._c; } int _a 1; int _b 2; int _c 3; }; //c17标准 //auto [x, y, z] A(2, 3, 4); A aa1(2, 3, 4); vectorA v4; v4.push_back(aa1); for (auto [x, y, z] : v4) { cout x y z endl; } }struct test001 { int a 12; int b 32; }; struct test002 { test001 n test001(); }; //auto [x, y] test002();//erro auto [x] test002(); auto [y,z] x; cout y : z endl;注意这里结构化绑定不能直接访问类成员中成员变量需要一步一步分解。迭代器失效vector迭代器失效指的是不能继续使用迭代器扩容会改变迭代器指针是位置而对应的pos位置指针不会给你改变会导致野指针对于迭代器失效就可以使用返回值来保留当前位置更新就能继续使用vector的模拟迭代器namespace bear { templateclass T class vector { public: // Vector的迭代器是一个原生指针 typedef T* iterator; typedef const T* const_iterator; iterator begin() { return _start; } iterator end() { return _finish; } const_iterator cbegin()const { return _start; } const_iterator cend() const { return _finish; } private: iterator _start; // 指向数据块的开始 iterator _finish; // 指向有效数据的尾 iterator _endOfStorage; // 指向存储容量的尾 }; }容器//size size_t size() const { return _finish - _start; } //capacity size_t capacity() const { return _endOfStorage - _start; } //扩容 void reserve(size_t n) { if (n capacity()) { T* tmp new T[n]; size_t old_size _finish - _start; if (_start) { //memcpy(tmp, _start,_finish-_start);//只能浅拷贝 for (size_t i 0; i size(); i) { //可以调用需要深拷贝的构造 tmp[i] _start[i]; } delete[] _start; } _start T; _finish _start old_size; _endOfStorage _start n; } } //resize void resize(size_t n, const T value T()) { if (n capacity()) { reserve(n); iterator it1 _start size(); while (it1 ! _start n) { (*it1) value; it1; } _finish _start n; } else { _finish _start n; } }元素访问///////////////access/////////////////////////////// //下标引用 T operator[](size_t pos) { assert(pos _finish); return _start[pos]; } const T operator[](size_t pos)const { assert(pos _finish); return _start[pos]; }元素修改///////////////modify///////////////////////////// void push_back(const T x) { //空间不够 if (_finish _endOfStorage) { reserve(capacity() 0 ? 4 : 2 * capacity()); } *_finish x; _finish; } void pop_back() { --_finish; } void swap(vectorT v) { std::swap(_start, v._start); std::swap(_finish, v._start); std::swap(_endOfStorage, v._endOfStorage); } iterator insert(iterator pos, const T x) { assert(pos _start); assert(pos _finish); if (_finish _endOfStorage) { //保存pos相对位置这里也是为了防止迭代器失效 size_t len pos - _start; reserve(capacity() 0 ? 4 : 2 * capacity()); pos len _start; } iterator it _finish - 1; while (it pos) { *(it 1) *it; --it; } *_finish x; _finish; //防止迭代器失效 return pos; } iterator erase(iterator pos) { assert(pos _start); assert(pos _finish); iterator it pos1; while (it ! _finish) { *(it - 1) *it; it; } --_finish; return pos;//防止迭代器失效 }构造、赋值和析构:// construct and destroy vector() :_start(nullptr) ,_finish(nullptr) ,_endOfStorage(nullptr) { } vector(int n, const T value T()) { resize(n, value); } templateclass InputIterator vector(InputIterator first, InputIterator last) { while (first ! last) { push_back(first); first; } } //拷贝 vector(const vectorT v) { reserve(v.capacity()); for (auto e : v) { push_back(e); } } //赋值 vectorT operator (vectorT v) { swap(v); return *this; } //析构 ~vector() { delete[] _start; _start _finish _endOfStorage nullptr; }总代码综合#pragma once #includeiostream #includeassert.h namespace bear { templateclass T class vector { public: // Vector的迭代器是一个原生指针 typedef T* iterator; typedef const T* const_iterator; iterator begin() { return _start; } iterator end() { return _finish; } const_iterator cbegin()const { return _start; } const_iterator cend() const { return _finish; } // construct and destroy vector() :_start(nullptr) ,_finish(nullptr) ,_endOfStorage(nullptr) { } vector(int n, const T value T()) { resize(n, value); } templateclass InputIterator vector(InputIterator first, InputIterator last) { while (first ! last) { push_back(first); first; } } //拷贝 vector(const vectorT v) { reserve(v.capacity()); for (auto e : v) { push_back(e); } } //赋值 vectorT operator (vectorT v) { swap(v); return *this; } //析构 ~vector() { delete[] _start; _start _finish _endOfStorage nullptr; } //size size_t size() const { return _finish - _start; } //capacity size_t capacity() const { return _endOfStorage - _start; } //扩容 void reserve(size_t n) { if (n capacity()) { T* tmp new T[n]; size_t old_size _finish - _start; if (_start) { //memcpy(tmp, _start,_finish-_start);//只能浅拷贝 for (size_t i 0; i size(); i) { //可以调用需要深拷贝的构造 tmp[i] _start[i]; } delete[] _start; } _start tmp; _finish _start old_size; _endOfStorage _start n; } } //resize void resize(size_t n, const T value T()) { if (n capacity()) { reserve(n); iterator it1 _start size(); while (it1 ! _start n) { (*it1) value; it1; } _finish _start n; } else { _finish _start n; } } ///////////////access/////////////////////////////// //下标引用 T operator[](size_t pos) { assert(pos _finish); return _start[pos]; } const T operator[](size_t pos)const { assert(pos _finish); return _start[pos]; } ///////////////modify///////////////////////////// void push_back(const T x) { //空间不够 if (_finish _endOfStorage) { reserve(capacity() 0 ? 4 : 2 * capacity()); } *_finish x; _finish; } void pop_back() { --_finish; } void swap(vectorT v) { std::swap(_start, v._start); std::swap(_finish, v._start); std::swap(_endOfStorage, v._endOfStorage); } iterator insert(iterator pos, const T x) { assert(pos _start); assert(pos _finish); if (_finish _endOfStorage) { //保存pos相对位置这里也是为了防止迭代器失效 size_t len pos - _start; reserve(capacity() 0 ? 4 : 2 * capacity()); pos len _start; } iterator it _finish - 1; while (it pos) { *(it 1) *it; --it; } *_finish x; _finish; //防止迭代器失效 return pos; } iterator erase(iterator pos) { assert(pos _start); assert(pos _finish); iterator it pos1; while (it ! _finish) { *(it - 1) *it; it; } --_finish; return pos;//防止迭代器失效 } private: iterator _start; // 指向数据块的开始 iterator _finish; // 指向有效数据的尾 iterator _endOfStorage; // 指向存储容量的尾 }; }总结vector这里较为重要的有vector的使用和vector的模拟其中迭代器的失效很重要通过底层实现vector的中发现在任意删和任意插insert,erase中pos指向会发生改变这就导致了迭代器的失效这里解决这个问题就是更新pos位置然后返回pos对应的指针。ps:vector底层实现是靠的指针所以元素起始位置地址和vector类的地址是不一样的vector类保存的地址是私有成员中_ptr的成员地址(vector保存了_ptr内部保存的地址的地址相当于套了一个壳)在这里只是保存了指针变量的地址而不是指针变量指向的地址(_ptr变量内部保存的地址)但是在这个_ptr成员中指向的是数组起始位置。vector 对象 └─ _ptr 一个指针变量它自己有个地址 _ptr ≈ v └─ _ptr 的值 指向堆上数组 v.data()