• C/C++ 入门(7)vector类(STL)


    个人主页:仍有未知等待探索-CSDN博客

    专题分栏:C++

                                                            请多多指教!

    目录

    一、标准库中的vector

    1、了解

    2、vector常用接口

    二、vector的实现 

    1、框架 

    2、构造、析构函数

    3、操作函数

    三 、问题

    1、由于赋值而引起的浅拷贝

    2、因为类没有实例化且用了类里面声明的类型等而产生的报错

    3、内部编译器错误 


    一、标准库中的vector

    1、了解

    vector就是一个支持变长的数组。

    2、vector常用接口

    vector的使用不做过多强调,注重的是实现vector类。

    可以点击下面的链接进入cplusplus网站,查看文档。

    vector - C++ Reference

    二、vector的实现 

    1、框架 

    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. template<class T>
    7. class vector
    8. {
    9. public:
    10. typedef T* iterator;//普通迭代器
    11. typedef const T* const_iterator;//const迭代器
    12. // Iterators:
    13. iterator begin()
    14. {
    15. return _start;
    16. }
    17. iterator end()
    18. {
    19. return _finish;
    20. }
    21. const_iterator begin() const
    22. {
    23. return _start;
    24. }
    25. const_iterator end() const
    26. {
    27. return _finish;
    28. }
    29. // 成员函数
    30. private:
    31. iterator _start = nullptr;
    32. iterator _finish = nullptr;
    33. iterator _endofstorage = nullptr;
    34. };

    2、构造、析构函数

    1. // 无参的构造必须写,因为下面实现了构造函数,编译器不会自动生成一个无参构造函数
    2. vector(){}
    3. // 开辟n个大小的空间,并初始化为m
    4. vector(const int& n, const int& m = 0)
    5. {
    6. // 新写法(复用reserve)
    7. reserve(n);
    8. for (int i = 0; i < n; i ++ ) _start[i] = m;
    9. _finish = _start + n;
    10. }
    11. // 用迭代器进行构造
    12. template<class input_iterator>
    13. vector(input_iterator start, input_iterator end)
    14. {
    15. input_iterator it = start;
    16. while (it != end)
    17. {
    18. push_back(*it);
    19. it ++ ;
    20. }
    21. }
    22. // 开辟n个大小的空间,并初始化为val
    23. // const T& val = T() -> 用一个匿名对象进行初始化,目的是为了预防vector中T是一个自定义类型。
    24. vector(size_t n, const T& val = T())
    25. {
    26. resize(n, val);// 复用resize
    27. }
    28. // 用一个vector进行拷贝构造
    29. vector(const vector& v)
    30. {
    31. reserve(v.capacity());
    32. for (auto& e : v)
    33. {
    34. // 复用push_back()
    35. push_back(e);
    36. }
    37. }
    38. // 用列表进行初始化
    39. // vector v = {1, 2, 3};
    40. // 用库函数实现的initializer_list
    41. vector(initializer_list il)
    42. {
    43. reserve(il.size());
    44. for (auto& e : il)
    45. {
    46. push_back(e);
    47. }
    48. }
    49. // 析构函数
    50. ~vector()
    51. {
    52. delete[] _start;
    53. _start = _finish = _endofstorage = nullptr;
    54. }

    3、操作函数

    1. vector& operator=(vector v)
    2. {
    3. swap(v);
    4. return *this;
    5. }
    6. // Capacity:
    7. size_t capacity() const
    8. {
    9. return _endofstorage - _start;
    10. }
    11. size_t size() const
    12. {
    13. return _finish - _start;
    14. }
    15. bool empty() const
    16. {
    17. return size() == 0;
    18. }
    19. void reserve(size_t n)
    20. {
    21. if (capacity() < n)
    22. {
    23. T* tmp = new T[n];
    24. int old_size = size();
    25. //memcpy(tmp, _start, size() * sizeof(T));
    26. // 当T是string类型的时候,memcpy会导致浅拷贝问题,并且会同时对一块空间析构多次
    27. for (int i = 0; i < old_size; i ++ )
    28. {
    29. tmp[i] = _start[i];
    30. }
    31. delete[] _start;
    32. _start = tmp;
    33. _finish = tmp + old_size;
    34. _endofstorage = tmp + n;
    35. }
    36. }
    37. void resize(size_t n, const T& val = T())
    38. {
    39. reserve(n);
    40. iterator it = _start;
    41. while (it != _endofstorage)
    42. {
    43. *it = val;
    44. it ++ ;
    45. }
    46. }
    47. // Element access:
    48. T& operator[](int pos)
    49. {
    50. assert(pos < size());
    51. return _start[pos];
    52. }
    53. // Modifiers:
    54. // 在pos之前插入一个数x
    55. void insert(iterator pos, const T& x)
    56. {
    57. assert(pos >= _start);
    58. assert(pos <= _finish);
    59. if (_finish == _endofstorage)
    60. {
    61. int len = pos - _start;
    62. reserve(capacity() == 0 ? 4 : 2 * capacity());
    63. pos = _start + len;
    64. }
    65. iterator it = _finish - 1;
    66. while (it >= pos)
    67. {
    68. *(it + 1) = *it;
    69. it -- ;
    70. }
    71. *pos = x;
    72. _finish ++ ;
    73. }
    74. // 尾插
    75. void push_back(const T& x)
    76. {
    77. // 老写法
    78. /*if (_finish == _endofstorage)
    79. {
    80. reserve(capacity() == 0 ? 4 : 2 * capacity());
    81. }
    82. *_finish = x;
    83. _finish ++ ;*/
    84. // 新写法
    85. insert(end() , x);
    86. }
    87. // 尾删
    88. void pop_back()
    89. {
    90. assert(!empty());
    91. _finish -- ;
    92. }
    93. // 交换函数,用库里面的swap实现指针的交换,来完成vector的交换
    94. void swap(vector& v)
    95. {
    96. std::swap(_start, v._start);
    97. std::swap(_finish, v._finish);
    98. std::swap(_endofstorage, v._endofstorage);
    99. }

    三 、问题

    1、由于赋值而引起的浅拷贝

    如果要将一个引用进行赋值,并且没有对赋值运算符重载的话,会只进行值拷贝而导致浅拷贝。最后会使编译器对同一块空间析构多次

    为什么*pos,x都是T类型的,而赋值重载却写一个vector类型的就能行?

    因为单参数的构造函数支持隐式类型转化,编译器会先进行构造函数,将这两个值构造成对象,然后在进行赋值。

    1. vector& operator=(vector v)
    2. {
    3. swap(v);
    4. return *this;
    5. }

    2、因为类没有实例化且用了类里面声明的类型等而产生的报错

    需要在使用这个类型前面加上typename标志这是一个类型。

    1. template<class T>
    2. void print_vector(vector& v)
    3. {
    4. // 不加typename会报错,因为在这个函数模板里,vector这个类并没有实例化,会不清楚const_iterator是类型还是变量
    5. // 加typename的含义就是告诉编译器,这个是类型
    6. typename vector::const_iterator it = v.begin();
    7. //auto it = v.begin();
    8. while (it != v.end())
    9. {
    10. cout << *it << " ";
    11. it ++ ;
    12. }
    13. }

     

    3、内部编译器错误 

    这个错误的原因是类模板或函数模板里面有语法错误。(比如说少加了一个分号等等)

  • 相关阅读:
    [分布式]-Raft论文研读
    修改键盘映射(改易误触按键)
    抖音获取抖音商品原数据 API 返回值说明
    超详细spring boot笔记
    关于elementui表单验证数字的问题
    IDM安装教程
    P2678 [NOIP2015 提高组] 跳石头
    docker基于alpine基础镜像合集(java、python)集成chrome
    神经网络中的权重和偏置初始化
    Python 直接赋值、浅拷贝和深度拷贝解析
  • 原文地址:https://blog.csdn.net/qq_73435980/article/details/138183578