• 从零开始的C++(十一)


    vector的模拟实现:

    1.构造函数

    1. vector()
    2. {
    3. }
    4. vector(int n, const T& value = T())
    5. {
    6. reserve(n);
    7. for (int i = 0; i < n; i++)
    8. {
    9. push_back(value);
    10. }
    11. }
    12. template<class InputIterator>
    13. vector(InputIterator first, InputIterator last)
    14. {
    15. auto it = first;
    16. while (it != last)
    17. {
    18. push_back(*it);
    19. it++;
    20. }
    21. }
    22. void swap(iterator&v1,iterator&v2)
    23. {
    24. iterator ret = v1;
    25. v1 = v2;
    26. v2 = ret;
    27. }
    28. vector(const vector<T>& v)
    29. {
    30. vector<T>tmp(v.cbegin(), v.cend());
    31. swap(_start,tmp._start);
    32. swap(_finish, tmp._finish);
    33. swap(_endOfStorage, tmp._endOfStorage);
    34. }
    1. private:
    2. iterator _start = nullptr; // 指向数据块的开始
    3. iterator _finish = nullptr; // 指向有效数据的尾
    4. iterator _endOfStorage = nullptr; // 指向存储容量的尾

    对象的成员使用了参数列表,防止随机值引发异常。同时,对于传同类型对象的构造函数,复用了传迭代器的构造函数创建临时对象,然后交换this所指对象和临时对象的成员的值,防止浅拷贝,并且利用临时变量销毁原本this对象的成员的内容。

    2.赋值重载:

    1. vector<T>& operator= (vector<T> v)
    2. {
    3. swap(_start, v._start);
    4. swap(_finish, v._finish);
    5. swap(_endOfStorage, v._endOfStorage);
    6. return *this;
    7. }

    赋值重载的原理和拷贝构造类似,都是用临时对象交换赋值,此处不用创建临时对象的原因是在实参到形参的过程已经进行了拷贝构造,即此处形参就是临时对象,所以直接交换即可。

    3.插入和删除

    1. void push_back(const T& x)
    2. {
    3. if (size() == capacity())
    4. {
    5. reserve(size() * 2+1);
    6. }
    7. *(_finish) = x;
    8. _finish++;
    9. }
    10. void pop_back()
    11. {
    12. assert(size() > 0);
    13. _finish--;
    14. }
    15. void swap(vector<T>& v)
    16. {
    17. swap(_start, v._start);
    18. swap(_finish, v._finish);
    19. swap(_endOfStorage, v._endOfStorage);
    20. }
    21. iterator insert(iterator pos, const T& x)
    22. {
    23. assert(pos-_start <= size());
    24. assert(pos - _start>= 0);
    25. if (size() == capacity())
    26. {
    27. int sz = pos - _start;
    28. reserve(size() * 2+1);
    29. pos = _start + sz;
    30. }
    31. auto it = _finish-1;
    32. while (it >= pos)
    33. {
    34. *(it + 1) = *it;
    35. it--;
    36. }
    37. *pos = x;
    38. _finish++;
    39. return pos;
    40. }
    41. iterator erase(iterator pos)
    42. {
    43. assert(pos-_start >= 0);
    44. assert(pos-_start < size());
    45. auto it = pos+1;
    46. while (it != _finish)
    47. {
    48. *(it - 1) = *(it);
    49. it++;
    50. }
    51. --_finish;
    52. return pos;
    53. }

    需要注意的是,insert和erase都可能会造成迭代器失效(即迭代器使用结果可能未定义或无法使用)。同时也需要注意判断插入、删除是否合理(是否越界等)。

    4.扩容

    1. void reserve(size_t n)
    2. {
    3. if (n >capacity())
    4. {
    5. int sz = size();
    6. iterator tmp = new T[n];
    7. if (_start!=nullptr)
    8. {
    9. //值拷贝
    10. for (int i = 0; i < sz; i++)
    11. {
    12. tmp[i] = _start[i];
    13. }
    14. }
    15. delete[]_start;
    16. //更新
    17. _start = tmp;
    18. _endOfStorage = _start + n;
    19. _finish = _start + sz;
    20. }
    21. }
    22. void resize(size_t n, const T& value = T())
    23. {
    24. if (n <=size())
    25. {
    26. _finish = _start + n;
    27. }
    28. else
    29. {
    30. reserve(n);
    31. while (size() < n)
    32. {
    33. push_back(value);
    34. }
    35. }
    36. }

    扩容应注意是深拷贝,因为成员可能是自定义类型,有自己的析构函数,如果是浅拷贝可能会出现二次delete的情况,也可能会出现析构导致内容变成随机值无法正常使用。

  • 相关阅读:
    用python来吐槽,真是太会玩啦
    代码随想录二刷day48
    手动设置process chain的运行job
    十八、【模糊工具组】
    设计一个简单的devops系统
    Ubuntu中安装使用QEMU/KVM/virt-manager运行虚拟机
    人工智能引领环境保护的新浪潮:技术应用及其影响
    Redis缓冲区溢出及解决方案
    C++面试八股文:什么是构造函数?
    基于vue3/Vue3的组件库
  • 原文地址:https://blog.csdn.net/yyssas/article/details/133953922