【C++】 vector讲解以及模拟

目录

vector基本介绍

定义

vector的优点

vector的本质

vector 的使用

(一).vetcor的定义:

(二).基本功能的使用

1.iterator 的使用

2.vector 空间增长

3.vector增删查改

vector的模拟实现

1.基本模版

2.成员函数

2.1构造函数

2.2拷贝构造

2.3析构函数

2.4 begin() && end()

2.5开空间resize

2.6尾插

2.7缩容resize

2.8任意位置插入insert

2.9删除erase

2.10尾删

2.11判断是否为空empty

2.12复制重载operator[]

memcpy拷贝问题

示例代码

vector.h

Test.cpp


vector相关文档

vector基本介绍

定义

vector是C++标准库中的一个容器类,提供了动态数组的功能。它是一个模板类,可以存储各种类型的元素。vector类封装了对数组的访问、插入和删除等操作,提供了方便和高效的数组操作接口。 与普通的数组相比,vector的大小是可变的,可以动态调整。它会自动处理内存分配和释放,简化了管理动态数组的复杂性。 可以通过C++标准库中的头文件来包含vector类。使用vector时,需要注意以下几点:

  • vector的下标索引从0开始,类似于普通数组。

  • 可以使用push_back函数在末尾插入元素。

  • 可以使用size函数获取vector中的元素数量。

  • 可以使用下标操作符[]直接访问和修改元素。

  • 可以使用inserterase函数在指定位置插入和删除元素。

vector的优点

与其它动态序列容器相比(deque, list and forward_list), vector在访问元素的时候更加高效,在末尾添加和删除元素相对高效; 对于其它不在末尾的删除和插入操作,效率更低; 比起list 和 forward_list 统一的迭代器和引用更好。

vector的本质

vector在动态存储元素的过程中。当新元素的插入,数组会重新开辟空间,将内容深拷贝到新的空间

就时间而言,这是 一个相对代价高的任务,因为每当一个新的元素加入到容器的时候,vector并不会每次都重新分配大小。

vector 的使用

(一).vetcor的定义:

vector

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

(二).基本功能的使用

1.iterator 的使用
使用 接口说明
begin+end 获取第一个暑假的位置的iterator/const_iterator+获取最后一个数据的下一个位置的iterator/const_iterator
rbegin+rend

获取最后一个数据的iterator/const_iterator+获取第一个数据前一个位置的iterator/const_iterator

【C++】 vector讲解以及模拟_第1张图片
【C++】 vector讲解以及模拟_第2张图片
2.vector 空间增长
容量空间 接口说明
size 获取数据个数
capacity 获取容量大小
empty 判断是否为空
resize(重点) 改变vector的size
reserve (重点) 改变vector的capacity

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

4.vector迭代器失效问题

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装 比如:vector的迭代器就是原生态指针T* 。因此迭代器失效,实际就是迭代器底层对应指针所指向的 空间被销毁了,而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。

大部分问题为:

1.vector扩容时,迭代器访问了旧空间

 vector 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<

2.erase:删除过程中导致迭代器失效

 #include 
 using namespace std;
 #include 
 int main()
 {
     int a[] = {1, 2, 3, 4};
     vector v(a, a + sizeof(a) / sizeof(int));
     // 使用find查找3所在位置的iterator
     vector::iterator pos = find(v.begin(), v.end(), 3);
     // 删除pos位置的数据,导致pos迭代器失效。 v.erase(pos);
     cout << *pos << endl; // 此处会导致非法访问 
     return 0;
 }

erase删除pos位置元素后,pos位置之后的元素会往前搬移,没有导致底层空间的改变,理论上讲迭代 器不应该会失效,但是:如果pos刚好是最后一个元素,删完之后pos刚好是end的位置,而end位置是 没有元素的,那么pos就失效了。因此删除vector中任意位置上元素时,vs就认为该位置迭代器失效了。

vector的模拟实现

1.基本模版

 template  //定义模版
 class vector
 {
 public:
     typedef T *iterator; //为 T* 类型创建了一个别名 iterator
     typedef const T *const_iterator;//为 T* 类型创建了一个别名 const_iterator
       size_t capacity() const
       {
           return _end_of_storage - _start;
       }
 ​
       size_t size() const
       {
           return _finish - _start;
       }
 private:
         // 指针
         iterator _start;
         iterator _finish;
         iterator _end_of_storage;
 };

【C++】 vector讲解以及模拟_第3张图片

  • _start:表示指向数据的开始位置;

  • _end:表示指向数据的结尾位置的下一个位置;

  • _end_of_storage:表示的是整个空间的大小。

2.成员函数

2.1构造函数

 vector()
     : _start(nullptr), _finish(nullptr), _end_of_storage(nullptr) // 全部初始化为空
 {
 }

2.2拷贝构造

交换swap:

 void swap(vector& v)
 {
     std::swap(_start, v._start);
     std::swap(_finish, v._finish);
     std::swap(_end_of_storage, v._end_of_storage);
 }

1.创建一个 vector 容纳了 n 个元素,每个元素的值均为 value

 vector(size_t n, const T &value = T())
     : _start(nullptr), _finish(nullptr), _end_of_storage(nullptr)
 {
     reserve(n);//扩容
     for (size_t i = 0; i < n; ++i)
     {
         push_back(value);//尾插
     }
 }

test:

 // 调用拷贝构造
 vector v1(10, 5);
 vector::iterator it = v1.begin();
 for (it = v1.begin(); it != v1.end(); ++it)
 {
     cout << *it << " ";
 }
 cout << endl;

2.通过循环遍历指针范围 [first, last),将该范围内的元素复制到新创建的 vector 容器中。

//[first,last)
template //
vector(InputIterator *first, InputIterator *last)
    : _start(nullptr), _finish(nullptr), _end_of_storage(nullptr)
{
    while (first != last)
    {
        push_back(*first);
        ++first;//first指针前移
    }
}

这段代码是模板(template)定义中的一部分,用于声明一个模板函数或类模板,并定义一个模板参数InputIterator,该参数可以接受任何类型的输入迭代器。部分表示使用一个名为InputIterator的类型作为模板参数。class关键字可以用于声明类型模板参数,它表明该参数可以是任何类型(类、结构体、基本数据类型等)。

test:

 vector v1(10, 5);        
 vector v2(v1.begin(), v1.end());
 for (it = v2.begin() + 1; it != v2.end() - 1; ++it)
 {
     cout << *it << " ";
 }
 cout << endl;

3.vector<> v2(v1):

a.传统写法

 vector(const vector &v)
 {
     _start = new T[v.capacity()];//开辟空间
     // memcpy(_start, v._start, v.size() * sizeof(T)); memcpy可能造成浅拷贝,导致调用析构函数时重复释放空间
     for (size_t i = 0; i < v.size(); ++i)
     {
         _start[i] = v._start[i];//深拷贝
     }
     _finish = _start + v.size();
     _end_of_storage = _start + v.capacity();
 }

b.现代写法

vector(const vector &v)
{
    vector tmp(v.begin(), v.end());
    swap(tmp);
}

test:

 // 没写拷贝构造,编译器默认生成拷贝构造,完成值拷贝/浅拷贝
 vector v1(10, 5);
 vector v2(v1);
 for (vector::iterator it = v2.begin(); it != v2.end(); ++it)//使用迭代器尽量不要使用<、>,应该使用!=
 {
     cout << *it << " ";
 }
 cout << endl;

 4.v2=v1

//v2=v1
vector& operator=(const vector &v)
{
    swap(v);
    return *this;
}

2.3析构函数

 ~vector()
 {
     delete[] _start;
     _start = _finish = _end_of_storage = nullptr;
 }

2.4 begin() && end()

 iterator begin()
 {
     return _start;
 }
 iterator end()
 {
     return _finish;
 }
 const_iterator begin() const
 {
     return _start;
 }
 const_iterator end() const
 {
     return _finish;
 }

2.5开空间resize

 void reserve(size_t n)
 {
     //检查空间是否足够大
     if (n > capacity())
     {
         size_t sz = size();
         // 分配新的存储空间
         T *tmp = new T[n];
         if (_start) // 检查旧空间是否为空
         {
             // 将内容复制到新空间
             // memcpy(tmp, _start, sizeof(T) * size());//浅拷贝
             for (size_t i = 0; i < sz; ++i)
                 tmp[i] = _start[i];
             delete[] _start;
         }
         // 更新指针
         _start = tmp;
         //_finish = tmp + size();//_finish - _start
         _finish = _start + sz; //_finish - _start
         _end_of_storage = _start + n;
     }
 }

2.6尾插

 void push_back(const T &x)
 {
     // 空间满了
     if (_finish == _end_of_storage)
     {
         reserve(capacity() == 0 ? 4 : capacity() * 2);
     }
     *_finish = x;
     ++_finish;
 }

2.7缩容resize

 // 缩容
 void resize(size_t n, T val = T()) // T():匿名对象调用默认构造
 {
     if (n < size())
     {
         // 删除数据
         _finish = _start + n;
     }
     else
     {
         if (n > capacity())
             reserve(n);
         // 添加数据
         while (_finish != _start + n)
         {
             *_finish = val;
             ++_finish;
         }
     }
 }

test:

 void func(const vector &v)
 {
   cout << "--func--" << endl;
   // 迭代器访问
   vector::const_iterator it = v.begin();
   while (it != v.end())
   {
       cout << *it << " ";
       ++it;
   }
   cout << endl;
   cout << "--func--" << endl;
 }
 ​
 void test_vector2()
 {
   vector v1;
   v1.push_back(1);
   v1.push_back(2);
   v1.push_back(3);
   v1.push_back(4);
 ​
   cout << "v1 size = " << v1.size() << endl;
   cout << "v1 capacity = " << v1.capacity() << endl;
 ​
   cout << "*resize*" << endl;
   v1.resize(10);
 ​
   cout << "v1 size = " << v1.size() << endl;
   cout << "v1 capacity = " << v1.capacity() << endl;
   func(v1);
 ​
   cout << endl;
 ​
   cout << "*保留前3个*" << endl;
   v1.resize(3);
   cout << "v1 size = " << v1.size() << endl;
   cout << "v1 capacity = " << v1.capacity() << endl;
   func(v1);
 }

2.8任意位置插入insert

 /*
 void insert(iterator& pos, const T &val)
 在v1.insert(v1.begin(), 0);v1.begin()具有常性,无法调用insert
 */
 iterator insert(iterator pos, const T &val)
 {
     assert(pos >= _start);
     assert(pos <= _finish);
 ​
     // 如果扩容
     if (_finish == _end_of_storage)
     {
         // 计算需要扩容的大小
         size_t len = pos - _start;
         // 扩容
         reserve(capacity() == 0 ? 4 : capacity() * 2);
 ​
         // 扩容后,更新pos,防止迭代器失效(野指针)
         pos = _start + len;
     }
 ​
     // 把pos位置的元素移动到_finish位置
     iterator end = _finish - 1;
     while (end >= pos)
     {
         *(end + 1) = *end;
         --end;
     }
     *pos = val;
     ++_finish;
 ​
     return pos;
 }

2.9删除erase

 iterator erase(iterator pos)
 {
     assert(pos >= _start);
     assert(pos < _finish);
 ​
     iterator start = pos + 1;
     while (start != _finish)
     {
         *(start - 1) = *start;
         ++start;
     }
     --_finish;
     return pos;
 }

2.10尾删

 void pop_back()
 {
     assert(!empty());
     --_finish;
 }

2.11判断是否为空empty

 bool empty() const
 {
     return _start == _finish;
 }

2.12复制重载operator[]

 T &operator[](size_t pos)
 {
     assert(pos <= size());
     return _start[pos];
 }
 const T &operator[](size_t pos) const
 {
     assert(pos <= size());
     return _start[pos];
 }

memcpy拷贝问题

假设模拟实现的vector中的reserve接口中,使用memcpy进行的拷贝,以下代码会发生什么问题?

 int main()
 {
     wzf::vector v;
     v.push_back("1111");
     v.push_back("2222");
     v.push_back("3333");
     return 0;
 }

问题分析:

  1. memcpy是内存的二进制格式拷贝,将一段内存空间中内容原封不动的拷贝到另外一段内存空间中

  2. 如果拷贝的是自定义类型的元素,memcpy既高效又不会出错,但如果拷贝的是自定义类型元素,并且 自定义类型元素中涉及到资源管理时,就会出错,因为memcpy的拷贝实际是浅拷贝。

【C++】 vector讲解以及模拟_第4张图片

【C++】 vector讲解以及模拟_第5张图片

结论:如果对象中涉及到资源管理时,千万不能使用memcpy进行对象之间的拷贝,因为memcpy是浅拷贝,否则可能会引起内存泄漏甚至程序崩溃。

示例代码

vector.h

 #pragma once
 #include 
 #include 
 using namespace std;
 ​
 namespace wzf
 {
 ​
     template 
     class vector
     {
     public:
         typedef T *iterator;
         typedef const T *const_iterator;
 ​
         vector()
             : _start(nullptr), _finish(nullptr), _end_of_storage(nullptr) // 全部初始化为空
         {
         }
 ​
         vector(size_t n, const T &value = T())
             : _start(nullptr), _finish(nullptr), _end_of_storage(nullptr)
         {
             reserve(n);
             for (size_t i = 0; i < n; ++i)
             {
                 push_back(value);
             }
         }
         //[first,last)
         template 
         vector(InputIterator *first, InputIterator *last)
             : _start(nullptr), _finish(nullptr), _end_of_storage(nullptr)
         {
             while (first != last)
             {
                 push_back(*first);
                 ++first;
             }
         }
 ​
         // v2(v1)
         // vector(const vector &v)
         // {
         //     reserve(v.capacity());
         //     memcpy(_start, v._start, v.size() * sizeof(T));
         //     _finish = _start + v.size();
         // }
         // vector(const vector &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(const vector &v)
         {
             _start = new T[v.capacity()];
             // memcpy(_start, v._start, v.size() * sizeof(T));
             for (size_t i = 0; i < v.size(); ++i)
             {
                 _start[i] = v._start[i];
             }
             _finish = _start + v.size();
             _end_of_storage = _start + v.capacity();
         }
 ​
         ~vector()
         {
             delete[] _start;
             _start = _finish = _end_of_storage = nullptr;
         }
 ​
         iterator begin()
         {
             return _start;
         }
         iterator end()
         {
             return _finish;
         }
         const_iterator begin() const
         {
             return _start;
         }
         const_iterator end() const
         {
             return _finish;
         }
 ​
         // 开空间
         void reserve(size_t n)
         {
             if (n > capacity())
             {
                 size_t sz = size();
                 // 分配新的存储空间
                 T *tmp = new T[n];
                 if (_start) // 检查旧空间是否为空
                 {
                     // 将内容复制到新空间
                     // memcpy(tmp, _start, sizeof(T) * size());//浅拷贝
                     for (size_t i = 0; i < sz; ++i)
                         tmp[i] = _start[i];
                     delete[] _start;
                 }
                 // 更新指针
                 _start = tmp;
                 //_finish = tmp + size();//_finish - _start
                 _finish = _start + sz; //_finish - _start
                 _end_of_storage = _start + n;
             }
         }
         void push_back(const T &x)
         {
             // 空间满了
             if (_finish == _end_of_storage)
             {
                 reserve(capacity() == 0 ? 4 : capacity() * 2);
             }
             *_finish = x;
             ++_finish;
         }
 ​
         // 缩容
         void resize(size_t n, T val = T()) // T():匿名对象调用默认构造
         {
             //检查空间大小
             if (n < size())
             {
                 // 删除数据
                 _finish = _start + n;
             }
             else
             {
                 if (n > capacity())
                     reserve(n);
                 // 添加数据
                 while (_finish != _start + n)
                 {
                     *_finish = val;
                     ++_finish;
                 }
             }
         }
 ​
         /*
         void insert(iterator& pos, const T &val)
         在v1.insert(v1.begin(), 0);v1.begin()具有常性,无法调用insert
         */
         iterator insert(iterator pos, const T &val)
         {
             assert(pos >= _start);
             assert(pos <= _finish);
 ​
             // 如果扩容
             if (_finish == _end_of_storage)
             {
                 // 计算需要扩容的大小
                 size_t len = pos - _start;
                 // 扩容
                 reserve(capacity() == 0 ? 4 : capacity() * 2);
 ​
                 // 扩容后,更新pos,防止迭代器失效(野指针)
                 pos = _start + len;
             }
 ​
             // 把pos位置的元素移动到_finish位置
             iterator end = _finish - 1;
             while (end >= pos)
             {
                 *(end + 1) = *end;
                 --end;
             }
             *pos = val;
             ++_finish;
 ​
             return pos;
         }
 ​
         iterator erase(iterator pos)
         {
             assert(pos >= _start);
             assert(pos < _finish);
 ​
             iterator start = pos + 1;
             while (start != _finish)
             {
                 *(start - 1) = *start;
                 ++start;
             }
             --_finish;
             return pos;
         }
 ​
         // 删除
         void pop_back()
         {
             assert(!empty());
             --_finish;
         }
 ​
         bool empty() const
         {
             return _start == _finish;
         }
 ​
         size_t capacity() const
         {
             return _end_of_storage - _start;
         }
 ​
         size_t size() const
         {
             return _finish - _start;
         }
 ​
         T &operator[](size_t pos)
         {
             assert(pos <= size());
             return _start[pos];
         }
         const T &operator[](size_t pos) const
         {
             assert(pos <= size());
             return _start[pos];
         }
 ​
     private:
         // 指针
         iterator _start;
         iterator _finish;
         iterator _end_of_storage;
     };
 ​
     void func(const vector &v)
     {
         cout << "--func--" << endl;
         // for (size_t i = 0; i < v.size(); ++i)
         // {
         //     cout << v[i] << " ";
         // }
         // cout << endl;
 ​
         // 迭代器访问
         vector::const_iterator it = v.begin();
         while (it != v.end())
         {
             cout << *it << " ";
             ++it;
         }
         cout << endl;
         cout << "--func--" << endl;
     }
 ​
     void test_vector1()
     {
         vector v1;
         v1.push_back(1);
         v1.push_back(2);
         v1.push_back(3);
         v1.push_back(4);
 ​
         for (size_t i = 0; i < v1.size(); ++i)
         {
             cout << v1[i] << " ";
         }
         cout << endl;
 ​
         func(v1);
 ​
         v1.pop_back();
         v1.pop_back();
         v1.pop_back();
 ​
         // 迭代器访问
         vector::iterator it = v1.begin();
         while (it != v1.end())
         {
             cout << *it << " ";
             ++it;
         }
         cout << endl;
     }
     void test_vector2()
     {
         vector v1;
         v1.push_back(1);
         v1.push_back(2);
         v1.push_back(3);
         v1.push_back(4);
 ​
         cout << "v1 size = " << v1.size() << endl;
         cout << "v1 capacity = " << v1.capacity() << endl;
 ​
         cout << "*resize*" << endl;
         v1.resize(10);
 ​
         cout << "v1 size = " << v1.size() << endl;
         cout << "v1 capacity = " << v1.capacity() << endl;
         func(v1);
 ​
         cout << endl;
 ​
         cout << "*保留前3个*" << endl;
         v1.resize(3);
         cout << "v1 size = " << v1.size() << endl;
         cout << "v1 capacity = " << v1.capacity() << endl;
         func(v1);
     }
 ​
     void test_vector3()
     {
         vector v1;
         v1.push_back(1);
         v1.push_back(2);
         v1.push_back(3);
         v1.push_back(4);
         func(v1);
 ​
         v1.insert(v1.begin(), 0);
         func(v1);
 ​
         vector::iterator pos = find(v1.begin(), v1.end(), 3); // find找到3的位置
         if (pos != v1.end())
         {
             pos = v1.insert(pos, 30);
         }
         func(v1);
         /*
         insert后我们认为pos失效了,不能在使用
         (*pos)++;
         func(v1);
         */
     }
     void test_vector4()
     {
         vector v1;
         v1.push_back(1);
         v1.push_back(2);
         v1.push_back(3);
         v1.push_back(4);
         func(v1);
 ​
         v1.insert(v1.begin(), 0);
         func(v1);
 ​
         vector::iterator pos = find(v1.begin(), v1.end(), 2); // find找到3的位置
         if (pos != v1.end())
         {
             v1.erase(pos);
         }
         func(v1);
         // 库中,调用erase,pos会失效,不能访问并且强制检查
         // 若删除最后一个元素,访问pos会造成野指针,故erase后不要访问pos
     }
     void test_vector5()
     {
         vector v1;
         v1.push_back(10);
         v1.push_back(2);
         v1.push_back(3);
         v1.push_back(4);
         v1.push_back(5);
         v1.push_back(50);
 ​
         vector::iterator it = v1.begin();
         while (it != v1.end())
         {
             cout << *it << " ";
 ​
             if (*it % 2 == 0)
             {
                 it = v1.erase(it);
             }
             else
             {
                 ++it;
             }
         }
 ​
         cout << endl;
 ​
         for (it = v1.begin(); it != v1.end(); ++it)
         {
             cout << *it << " ";
         }
         cout << endl;
     }
     void test_vector6()
     {
         // 调用拷贝构造
         vector v1(10, 5);
         vector::iterator it = v1.begin();
         for (it = v1.begin(); it != v1.end(); ++it)
         {
             cout << *it << " ";
         }
         cout << endl;
 ​
         vector v2(v1.begin(), v1.end());
         for (it = v2.begin() + 1; it != v2.end() - 1; ++it)
         {
             cout << *it << " ";
         }
         cout << endl;
     }
     void test_vector7()
     {
         // 没写拷贝构造,编译器默认生成拷贝构造,完成值拷贝/欠拷贝
         vector v1(10, 5);
         vector v2(v1);
         for (vector::iterator it = v2.begin(); it != v2.end(); ++it)
         {
             cout << *it << " ";
         }
         cout << endl;
 ​
         vector v3(3, "HelloHelloHelloHello");
         vector v4(v3);
         for (vector::iterator it = v4.begin(); it != v4.end(); ++it)
         {
             cout << *it << "----";
         }
         cout << endl;
         v4.push_back("≠2024!±");
         v4.push_back("≠2024!±");
         v4.push_back("≠≠2024!±");
         v4.push_back("≠2024!±");
         for (vector::iterator it = v4.begin(); it != v4.end(); ++it)
         {
             cout << *it << "----";
         }
         cout << endl;
     }
 }

Test.cpp

 #include "vector.h"
 ​
 int main()
 {
     wzf::test_vector7();
 ​
     return 0;
 }

你可能感兴趣的:(C++,c++,开发语言)