【C++】-- STL之vector模拟实现(一)

简介: 【C++】-- STL之vector模拟实现

vector类实现

vector结构:

如上图,vector的结构中,包含3个成员变量:

_start:指向vector元素的起始位置

_finish:指向vector元素的结束位置

_end_of_storage:指向vector元素可用空间的位置

为了和库里面的vector区分开,使用命名空间delia将 vector类和库里vector隔离开

1. namespace delia
2. {
3. template<class T>//vector里面的元素可能是int,可能是double……所以使用类模板
4.  class vector
5.  {
6. private:
7.         iterator _start;
8.    iterator _finish;
9.    iterator _end_of_storage;
10.     }
11. }

实现以下vector相关内容:

 

1.vector类构造

vector类有3种常见的构造函数

(1)无参构造函数,构造空容器

1. vector()//将成员变量都初始化成空指针
2.          :_start(nullptr)
3.          , _finish(nullptr)
4.          , _end_of_storage(nullptr)
5.      {}

(2)范围构造函数。函数模板InputIterator是输入迭代器类型,并且类型不确定,用first到last之间的元素尾插到容器中

1. 
2.    template<class InputIterator>
3.    vector(InputIterator first, InputIterator last)
4.      :_start(nullptr)
5.      ,_finish(nullptr)
6.      ,_end_of_storage(nullptr)
7.    {
8.      while (first != last)
9.      {
10.         if (first)
11.         {
12.           push_back(*first);
13.           first++;
14.         }
15. 
16.       }
17.     }
18. 
19. //e.g:
20. //vector<int> v1;
21. //v1.push_back(0);
22. //v1.push_back(1);
23. //v1.push_back(2);
24. //v1.push_back(3);
25. 
26. //vector<int> v2(v1.begin(),v1.begin()+2); 向v2插入v1的前2个元素

(3) 填充构造函数。向容器中插入n个值为val的元素

1.    vector(size_t n, const T& val)
2.      :_start(nullptr)
3.      , _finish(nullptr)
4.      , _end_of_storage(nullptr)
5.    {
6.      reserve(n);
7.      while (n)
8.      {
9.        push_back(val);
10.         n--;
11.       }
12.     }
13. //e.g:
14. //vector<int> v2(3,5);向v2中插入3个5

但是编译时会提示:

这是因为当使用两个参数进行构造时,编译器会优先匹配构造函数(2),对*first解引用会报错。所以需要再实现两个不同参数类型的(3)的构造函数重载:

1. vector(int n, const T val)
2.      :_start(nullptr)
3.      , _finish(nullptr)
4.      , _end_of_storage(nullptr)
5.    {
6.      reserve(n);
7.      while (n)
8.      {
9.        push_back(val);
10.         n--;
11.       }
12.     }
13. 
14.     vector(long n, const T val)
15.       :_start(nullptr)
16.       , _finish(nullptr)
17.       , _end_of_storage(nullptr)
18.     {
19.       reserve(n);
20.       while (n)
21.       {
22.         push_back(val);
23.         n--;
24.       }
25.     }
26. 
27. //e.g:
28. //vector<int> v2(3,5);向v2中插入3个5

2.拷贝构造

假如不写vector类的拷贝构造函数,那么编译器自动生成的默认拷贝构造函数只能完成浅拷贝,vector类的3个成员变量的类型都是T*,如果T是内置类型,那么拷贝OK;但如果T是自定义类型,那么拷贝对象和被拷贝对象指向同一块空间,后定义的先析构,这块空间会被释放两次,程序就会崩掉。

(1)传统的拷贝构造

1. //v2(v1)
2.    vector(const vector<T>& v)
3.      :_start(nullptr)
4.      ,_finish(nullptr)
5.      ,_end_of_storage(nullptr)
6.    {
7.      //1.申请空间
8.      _start = new T[v.capacity()];
9. 
10.       //2.拷贝数据
11.       for (size_t i = 0; i < v.size(); i++)
12.       {
13.         _start[i] = v._start[i];
14.       }
15. 
16.       //3.更新大小及容量
17.       _finish = _start + v.size();
18.       _end_of_storage = _start + v.capacity();
19.     }

为什么2.拷贝数据时不使用memcpy呢?

memcpy(_start, v._start, sizeof(T) * v.size());

①如果T是内置类型,使用memcpy拷贝完全OK,析构时不需要清理资源;

②如果T是自定义类型,假如T的类型为Stack自定义类型,那么使用memcpy会把v的地址拷贝给this,对于v的每一个元素,对象st2的成员变量_a拷贝的是st1的成员变量_a指针,即把st1的_a指针的值,拷贝给了st2的_a,那么两个指针的值是一样的,st1的_a和st2的_a指向同一块空间:

1. typedef int STDataType;
2. class Stack
3. {
4. private:
5.  STDataType* _a;
6.  int _size;
7.  int _capacity;
8. };
9. 
10. int main()
11. {
12.     Stack st1;
13. Satck st2(st1);
14. }

拷贝stack对象

拷贝v中的所有元素:

在析构时,vector的每个元素析构两次,那么同一块空间会被释放两次,程序会崩,因此,使用以下代码直接将vector元素值拷贝过来即可

1. //2.拷贝数据
2.      for (size_t i = 0; i < v.size(); i++)
3.      {
4.        _start[i] = v._start[i];
5.      }

(2)现代的拷贝构造:开空间+逐个尾插

使用现代的拷贝构造时必须初始化,否则_start、_finish、_end_of_storage都是随机值,拷贝数据时可能会导致越界。如果T是自定义类型,那么会调用T的拷贝构造函数进行深拷贝

1. vector(const vector<T>& v)
2.      :_start(nullptr)
3.      , _finish(nullptr)
4.      , _end_of_storage(nullptr)
5.    {
6.      reserve(v.capacity());//开与v一样大小的空间
7. 
8.      //逐个尾插
9.      for (auto& e: v)
10.       {
11.         push_back(e);
12.       }
13.     }


相关文章
|
3天前
|
存储 自然语言处理 安全
C++ STL标准库 《string原理与实战分析》
C++ STL标准库 《string原理与实战分析》
13 0
|
1天前
|
存储 算法 程序员
【C++进阶】深入STL之 栈与队列:数据结构探索之旅
【C++进阶】深入STL之 栈与队列:数据结构探索之旅
|
1天前
|
存储 缓存 编译器
【C++进阶】深入STL之list:模拟实现深入理解List与迭代器
【C++进阶】深入STL之list:模拟实现深入理解List与迭代器
|
1天前
|
C++ 容器
【C++进阶】深入STL之list:高效双向链表的使用技巧
【C++进阶】深入STL之list:高效双向链表的使用技巧
|
1天前
|
编译器 C++ 容器
【C++进阶】深入STL之vector:深入研究迭代器失效及拷贝问题
【C++进阶】深入STL之vector:深入研究迭代器失效及拷贝问题
|
1天前
|
存储 算法 程序员
【C++进阶】深入STL之vector:构建高效C++程序的基石
【C++进阶】深入STL之vector:构建高效C++程序的基石
|
1天前
|
编译器 C++
【C++进阶】深入STL之string:模拟实现走进C++字符串的世界
【C++进阶】深入STL之string:模拟实现走进C++字符串的世界
|
1天前
|
安全 算法 C语言
【C++进阶】深入STL之string:掌握高效字符串处理的关键
【C++进阶】深入STL之string:掌握高效字符串处理的关键
【C++进阶】深入STL之string:掌握高效字符串处理的关键
|
2天前
|
C++ 容器 存储
【C++语言】想学STL,先细细拿捏string类,万字详解string类 (内附精美思维导图)
【C++语言】想学STL,先细细拿捏string类,万字详解string类 (内附精美思维导图)
|
2天前
|
大数据 C++ 索引
C++ STL标准库 《vector向量原理与实战分析》
C++ STL标准库 《vector向量原理与实战分析》
9 0