必看!用示例代码学C++ STL-vector,快速掌握基础知识,高效提升编程能力

C++ STL-vector


目录

C++ STL-vector

●1.vector的定义

●2.vector iterator的使用

●3.vector空间增长的问题

●4.vector的增删查改

●5.vector的迭代器失效问题

●6.vector深度剖析及模拟实现


1.vector的定义

构造函数声明 接口说明
vector() 无参构造
vector(size_type n, const value_type& val = value_type()) 构造并初始化n个val
vector (const vector& x) 拷贝构造
vector (InputIterator first, InputIterator last) 使用迭代器进行初始化构造

示例:

c++ 复制代码
template <class T>
void print_vector(const vector<T> &v)
{
       for (auto& e : v)
       {
               cout << e;
       }
       cout << endl;
}
void test1()
{
       vector<int> v;
       print_vector(v);      //
       vector<int> v1(10,1);
       print_vector(v1);//1111111111
       vector<int> v2(v1);           
       print_vector(v2);//1111111111
       vector<int>::iterator pb = v1.begin();
       vector<int>::iterator pe = v1.end();
       vector<int> v3(pb, pe);
       print_vector(v3);//1111111111
}

2.vector iterator的使用

iterator的使用 接口说明
begin +end 获取第一个数据位置的iterator/const_iterator, 获取最后一个数据的下一个位置iterator/const_iterator
rbegin + rend 获取最后一个数据位置的reverse_iterator,获取第一个数据前一个位置的reverse_iterator

示例:

c++ 复制代码
void test2()
{
       vector<int> v;
       v.push_back(1);
       v.push_back(2);
       v.push_back(3);
       v.push_back(4);
       for (vector<int>::iterator p=v.begin();p!=v.end();p++)
       {
               cout << *p<<" ";
       }
       cout << endl;  //1 2 3 4
       for (vector<int>::reverse_iterator p = v.rbegin(); p!= v.rend(); p++)
       {
               cout << *p << " ";
       }
       cout << endl;//4 3 2 1
}

3.vector空间增长的问题

容量空间 接口说明
size 获取数据个数
capacity 获取容量大小
empty 获取容量大小
resize 改变vector的size
reserve 改变vector的capacity

示例:

c++ 复制代码
void test3()
{
       vector<int> v;
       v.push_back(1);
       v.push_back(2);
       v.push_back(3);
       v.push_back(4);
       cout << v.size() << endl; //4
       cout << v.capacity() << endl; //4
       cout << v.empty() << endl; //0
 
       v.resize(10);
       cout << v.size() << endl; //10
       cout << v.capacity() << endl;//10
 
       v.reserve(20);
       cout << v.size() << endl; //10
       cout << v.capacity() << endl;//20
}

4.vector的增删查改

增删查改 接口说明
push_back 尾插
pop_back 尾删
find 查找(注意这个是算法模块实现,不是vector的成员接口)
insert 在position之前插入val
erase 删除position位置的数据
swap 交换两个vector的数据空间
operator[] 像数组一样访问

示例:

c++ 复制代码
#include<algorithm>
template <class T>
void print_vector(const vector<T>& v)
{
       for (auto& e : v)
       {
               cout << e;
       }
       cout << endl;
}
void test4()
{
       vector<int> v;
       for (int i = 0; i < 10; i++)
       {
               v.push_back(i);
       }
       print_vector(v);      //0123456789
 
       for (int i = 0; i < 5; i++)
       {
               v.pop_back();
       }
       print_vector(v);      //01234
 
       vector<int>::iterator p=find(v.begin(), v.end(), 3);
       cout << *p << endl;           //3
 
       p = v.begin();
       v.insert(p,100);
       print_vector(v);      //10001234
       v.erase(v.begin(),v.begin()+1);
       print_vector(v);      //01234
 
       vector<int> v1;
       v.swap(v1);
       print_vector(v);      //
       print_vector(v1);     //01234
 
       for (int i = 0; i < v1.size(); i++)
       {
               cout << v1[i];
       }
       cout << endl;  //01234
}

5.vector的迭代器失效问题

示例1:会引起其底层空间改变的操作,都有可能是迭代器失效,比如:resize、reserve、insert、assign、push_back等。

c++ 复制代码
#include <iostream>
using namespace std;
#include <vector>
int main()
{
       vector<int> v{ 1,2,3,4,5,6 };
       auto it = v.begin();
       // 将有效元素个数增加到100个,多出的位置使用8填充,操作期间底层会扩容
       // v.resize(100, 8);
       // reserve的作用就是改变扩容大小但不改变有效元素个数,操作期间可能会引起底层容量改变
       // v.reserve(100);
       // 插入元素期间,可能会引起扩容,而导致原空间被释放
       // v.insert(v.begin(), 0);
       // v.push_back(8);
       // 给vector重新赋值,可能会引起底层容量改变
       v.assign(100, 8);
       /*
       出错原因:以上操作,都有可能会导致vector扩容,也就是说vector底层原理旧空间被释放掉,
   而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的
   空间,而引起代码运行时崩溃。
       解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新
   赋值即可。
       */
       while (it != v.end())
       {
               cout << *it << " ";
               ++it;
       }
       cout << endl;
       return 0;
}

示例2:指定位置元素的删除操作erase

c++ 复制代码
情况一:
#include <iostream>
using namespace std;
#include <vector>
int main()
{
       vector<int> v;
       v.push_back(1);
       v.push_back(2);
       v.push_back(3);
       v.push_back(4);
       // 使用find查找3所在位置的iterator
       vector<int>::iterator pos = find(v.begin(), v.end(), 3);
       // 删除pos位置的数据,导致pos迭代器失效。
       v.erase(pos);
       cout << *pos << endl; // 此处会导致非法访问
       return 0;
}
 
情况二:正确与错误的对比
#include <iostream>
using namespace std;
#include <vector>
//error
int main()
{
       vector<int> v{ 1, 2, 3, 4 };
       auto it = v.begin();
       while (it != v.end())
       {
               if (*it % 2 == 0)
                      v.erase(it);    //删除后,迭代器指向野区域
               ++it;  
       }
       return 0;
}
 
//true
int main()
{
       vector<int> v{ 1, 2, 3, 4 };
       auto it = v.begin();
       while (it != v.end())
       {
               if (*it % 2 == 0)
                      it = v.erase(it);    //删除后,拿回迭代器指向下一个位置
               else
                      ++it;
       }
       return 0;
}

示例3:Linux下,g++编译器对迭代器失效的检测并不是非常严格,处理也没有vs下极端

c++ 复制代码
情况一:扩容之后,迭代器已经失效了,程序虽然可以运行,但是运行结果已经不对了
int main()
{
       vector<int> v{ 1,2,3,4,5 };
       for (size_t i = 0; i < v.size(); ++i)
               cout << v[i] << " ";
       cout << endl;
       auto it = v.begin();
       cout << "扩容之前,vector的容量为: " << v.capacity() << endl;
       // 通过reserve将底层空间设置为100,目的是为了让vector的迭代器失效
       v.reserve(100);
       cout << "扩容之后,vector的容量为: " << v.capacity() << endl;
       // 经过上述reserve之后,it迭代器肯定会失效,在vs下程序就直接崩溃了,但是linux下不会
       // 虽然可能运行,但是输出的结果是不对的
       while (it != v.end())
       {
               cout << *it << " ";
               ++it;
       }
       cout << endl;
       return 0;
}
 
情况二:erase删除任意位置代码后,linux下迭代器并没有失效,因为空间还是原来的空间,后序元素往前搬移了,it的位置还是有效的
#include <vector>
#include <algorithm>
int main()
{
       vector<int> v{ 1,2,3,4,5 };
       vector<int>::iterator it = find(v.begin(), v.end(), 3);
       v.erase(it);
       cout << *it << endl;
       while (it != v.end())
       {
               cout << *it << " ";
               ++it;
       }
       cout << endl;
       return 0;
}
 
情况三:erase删除的迭代器如果是最后一个元素,删除之后it已经超过end,此时迭代器是无效的,++it导致程序崩溃
int main()
{
       vector<int> v{1,2,3,4,5,6};
       auto it = v.begin();
       while (it != v.end())
       {
               if (*it % 2 == 0)
                      v.erase(it);
               ++it;
       }
       for (auto e : v)
               cout << e << " ";
       cout << endl;
       return 0;
}

注意:与vector类似,string在插入/扩容操作/erase之后,迭代器也会失效。

6.vector深度剖析及模拟实现

示例代码:vector.hpp(源头不分离)

c++ 复制代码
#pragma once
#include<cstring>
#include<assert.h>
#include"reverse_iterator.hpp"
 
namespace myVector
{
       template<class T>
       class vector
       {
       public:
               typedef T* iterator;
               typedef const T* const_iterator;
               
               //typedef T* reverse_iterator;
               //typedef const T* const_reverse_iterator;
               typedef reverseiterator<iterator, T&, T*> reverse_iterator;
               typedef reverseiterator<const_iterator, const T&, const  T*>const_reverse_iterator;
       public:
               vector()
                      :_start(nullptr),
                       _finish(nullptr),
                       _end_of_storage(nullptr)
               {}
               vector(const vector<T>& v)
               {      
                      _start = new T[v.capacity()];
                      memcpy(_start,v._start,v.size()*sizeof(T));
                      _finish = _start + v.size();
                      _end_of_storage = _start + v.capacity();
               }
               ~vector()
               {
                      if (_start)
                      {
                              delete[] _start;
                              _start = _finish = _end_of_storage = nullptr;
                      }
               }
               size_t size() const
               {
                      return _finish - _start;
               }
               size_t capacity() const
               {
                      return _end_of_storage - _start;
               }
       public:
               iterator begin()
               {
                      return _start;
               }
               const_iterator begin() const
               {
                      return _start;
               }
               iterator end()
               {
                      return _finish;
               }
               const_iterator end() const
               {
                      return _finish;
               }
       public:
               reverse_iterator rbegin()
               {
                      return reverse_iterator(end()-1);
                      //return end()-1;  //_finish-1;
               }
               const_reverse_iterator rbegin() const
               {
                      return const_reverse_iterator(end()-1);
                      //return end()-1;     //_finish-1;
               }
               reverse_iterator rend()
               {
                      return reverse_iterator(begin()-1);
                      //return begin()-1;   //_start-1;
               }
               const_reverse_iterator rend() const
               {
                      return const_reverse_iterator(begin()-1);
                      //return begin()-1;   //_start-1;
               }
       public:
               void reserve(size_t n)
               {
                      if (n>capacity())
                      {
                              size_t old_size = size();
                              T* tmp = new T[n];
                              if (_start)
                              {
                                     memcpy(tmp,_start,sizeof(T)*n);
                                     delete[] _start;
                              }
                              _start = tmp;
                              _finish = _start + old_size;
                              _end_of_storage = _start + n;
                      }
               }
               void resize(size_t n,T val=T())
               {
                      T* _val = new T[n];
                      for (auto i = 0; i < n; i++)
                              _val[i] = val;
                      if (n >= 0 && n <= size()) {
                              size_t len = (size() - n);
                              _finish = _finish - len;
                              memcpy(_finish,_val,sizeof(int)*len);
                      }
                      else if (n > size() && n <= capacity()) {
                              size_t len = (n - size());
                              memcpy(_finish, _val, sizeof(int)*len);
                              _finish = _finish + len;
                      }
                      else if (n > capacity()) {
                              reserve(n);
                              size_t len = n - size();
                              memcpy(_finish,_val,sizeof(int)*len);
                              _finish = _start + n;
                      }
               }
               void judge_capacity()
               {
                      size_t newcapacity = 0;
                      if (capacity() == 0) {
                              newcapacity = 5;
                      }
                      else {
                              newcapacity = 3 * capacity();
                      }
                      reserve(newcapacity);
               }
               void push_back(const T& x)
               {
                      if (_finish==_end_of_storage)
                      {
                              judge_capacity();
                      }
                      *_finish = x;
                      _finish++;
               }
               void insert(iterator p,T val)
               {
                      assert(p >= _start && p <= _finish);
                      if (size() == capacity())
                      {
                              size_t len = p - _start;
                              judge_capacity();
                              p = _start + len;
                      }
                      memmove(p+1,p,sizeof(T)*(_finish-p));
                      *p = val;
                      _finish++;
               }
               void erase(iterator pos)
               {
                      assert(pos >= _start && pos < _finish);
                      _finish = pos;
               }
               void pop_back()
               {
                      assert(size() > 0);
                      _finish--;
               }
       public:
               T& operator[](size_t n)
               {
                      assert(n>=0&&n<size());
                      return *(_start+n);
               }
               void swap(vector<T>& v)
               {
                      std::swap(_start,v._start);
                      std::swap(_finish, v._finish);
                      std::swap(_end_of_storage,v._end_of_storage);
               }
               vector<T>& operator=(vector<T> v)
               {
                      swap(v);
                      return *this;
               }
       private:
               iterator _start;
               iterator _finish;
               iterator _end_of_storage;
       };
       void vector_print(const vector<int>& v)
       {
               for (auto e : v)
               {
                      cout << e << " ";
               }
               cout << endl;
       }
    };
}

示例代码:reverse_iterator.hpp(源头不分离)

c++ 复制代码
#pragma once
template<class Iterator,class Ref,class Ptr>
class reverseiterator {
public:
       typedef reverseiterator<Iterator,Ref,Ptr> self;
       reverseiterator(Iterator it)
               :_it(it)
       {}
       self& operator++()
       {
               --_it;
               return *this;
       }
       self& operator++(int)
       {
               _it--;
               return *this;
       }
       self& operator--()
       {
               ++_it;
               return *this;
       }
       self& operator--(int)
       {
               _it++;
               return *this;
       }
       Ref operator*()
       {
               return *_it;
       }
       Ptr operator->()
       {
               return _it.operator->();
       }
       bool operator!=(const self& l)
       {
               return _it != l._it;
       }
private:
       Iterator _it;
};

<您的三连和关注是我最大的动力>
🚀 文章作者:张同学的IT技术日记
分类专栏:C++系列

相关推荐
hui函数6 小时前
Flask电影投票系统全解析
后端·python·flask
小厂永远得不到的男人8 小时前
基于 Spring Validation 实现全局参数校验异常处理
java·后端·架构
毅航12 小时前
从原理到实践,讲透 MyBatis 内部池化思想的核心逻辑
后端·面试·mybatis
展信佳_daydayup12 小时前
02 基础篇-OpenHarmony 的编译工具
后端·面试·编译器
Always_Passion12 小时前
二、开发一个简单的MCP Server
后端
用户7215220787712 小时前
基于LD_PRELOAD的命令行参数安全混淆技术
后端
笃行35012 小时前
开源大模型实战:GPT-OSS本地部署与全面测评
后端
知其然亦知其所以然13 小时前
SpringAI:Mistral AI 聊天?一文带你跑通!
后端·spring·openai
庚云13 小时前
🔒 前后端 AES 加密解密实战(Vue3 + Node.js)
前端·后端
超级小忍13 小时前
使用 GraalVM Native Image 将 Spring Boot 应用编译为跨平台原生镜像:完整指南
java·spring boot·后端