必看!用示例代码学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++系列

相关推荐
zopple7 小时前
常见的 Spring 项目目录结构
java·后端·spring
cjy0001119 小时前
springboot的 nacos 配置获取不到导致启动失败及日志不输出问题
java·spring boot·后端
小江的记录本10 小时前
【事务】Spring Framework核心——事务管理:ACID特性、隔离级别、传播行为、@Transactional底层原理、失效场景
java·数据库·分布式·后端·sql·spring·面试
sheji341610 小时前
【开题答辩全过程】以 基于springboot的校园失物招领系统为例,包含答辩的问题和答案
java·spring boot·后端
程序员cxuan10 小时前
人麻了,谁把我 ssh 干没了
人工智能·后端·程序员
wuyikeer11 小时前
Spring Framework 中文官方文档
java·后端·spring
Victor35611 小时前
MongoDB(61)如何避免大文档带来的性能问题?
后端
Victor35611 小时前
MongoDB(62)如何避免锁定问题?
后端
wuyikeer12 小时前
Spring BOOT 启动参数
java·spring boot·后端
子木HAPPY阳VIP13 小时前
Ubuntu 22.04 VMware 设置固定IP配置
人工智能·后端·目标检测·机器学习·目标跟踪