3.4.3 增删查改函数
push_back()
void push_back(const T& x) { if (_finish == _end_of_storage) { reserve(capacity() == 0 ? 4 : capacity() * 2); } *_finish = x; ++_finish; //insert(end(), x); }
首先,函数检查 _finish 指针是否等于 _end_of_storage,即是否达到了当前容器的容量上限。如果达到了容量上限,说明没有足够的空间存放新元素,因此需要进行内存重新分配。
内存重新分配时,使用 reserve 函数,如果当前容量为 0,则分配至少 4 个元素的空间,否则将容量扩展为当前容量的两倍。然后,函数将新元素 x 赋值给 _finish 指针指向的位置,即当前容器的末尾。然后,通过递增 _finish 指针,将 _finish 指向下一个可用位置。
pop_back()
void pop_back() { assert(_finish > _start); --_finish; }
首先,函数使用 assert 宏来检查 _finish 指针是否大于 _start 指针。这是一个断言,用于确保在 _finish 小于或等于 _start 时不会发生错误。如果 _finish 不大于 _start,则断言会触发错误,帮助在开发过程中发现问题。
接着,函数将 _finish 指针递减 1,从而使其指向容器中的倒数第二个元素,即删除了最后一个元素。
iterator insert()
iterator insert(iterator pos, const T& x) { assert(pos >= _start); assert(pos <= _finish); if (_finish == _end_of_storage) { size_t len = pos - _start; reserve(capacity() == 0 ? 4 : capacity() * 2); pos = _start + len; } // 挪动数据 iterator end = _finish - 1; while (end >= pos) { *(end + 1) = *end; --end; } *pos = x; ++_finish; return pos; }
首先,函数使用 assert 宏来检查 pos 是否在 _start 和 _finish 之间,确保插入位置在合法范围内。然后,函数检查容器是否已满,即 _finish 是否等于 _end_of_storage。如果容器已满,需要扩容。首先计算插入位置相对于 _start 的偏移量 len,以便在插入后重新定位 pos,以防扩容导致迭代器失效。接着根据扩容规则进行扩容操作,将 _start 移动到新分配的内存中。在容器中插入元素之前,需要将插入位置之后的元素往后挪动一个位置。使用一个循环从 _finish - 1 开始,逐个将元素向后移动一位,为新元素腾出空间。将新元素 x 插入到指定的位置 pos。最后,递增 _finish 指针,表示容器中多了一个元素,然后返回插入位置的迭代器。
iterator erase()
iterator erase(iterator pos) { assert(pos >= _start); assert(pos < _finish); iterator begin = pos + 1; while (begin < _finish) { *(begin - 1) = *begin; ++begin; } --_finish; return pos; }
首先,函数使用 assert 宏来检查 pos 是否在 _start 和 _finish 之间,确保删除位置在合法范围内。
然后,函数创建一个名为 begin 的迭代器,初始值为 pos 的下一个位置,即要删除的元素之后的位置。
接着,使用一个循环将 begin 位置及其后面的元素逐个向前移动一个位置,覆盖掉要删除的元素。这样就相当于将删除位置的元素覆盖掉,从而实现删除操作。
最后,递减 _finish 指针,表示容器中少了一个元素,然后返回原始的删除位置的迭代器。
3.4.4 赋值运算符重载
operator=
vector<T>& operator=(vector<T> v) { swap(v); return *this; }
这个赋值运算符重载是一个实现 C++ 中的拷贝交换技术(Copy-and-Swap Idiom)的常见写法,用于实现自定义的赋值操作。该赋值运算符接受一个传值的参数 v,这里通过传值来进行拷贝构造一个临时的 vector 对象,然后调用 swap(v) 实现了将当前对象的数据与临时对象进行交换。这样,临时对象的数据会被赋值给当前对象,而临时对象会在函数结束时被析构,从而释放掉原来当前对象的资源。
这种写法的好处在于它可以避免拷贝构造和析构造成的额外开销,从而提高了效率。同时,交换操作的实现通常在类内部对各个成员进行指针交换,因此不会涉及数据的实际拷贝。
总的来说,这个赋值运算符实现了一种高效的赋值操作,是 C++ 中常用的实现方式之一。
vector模拟实现全部代码
#pragma once #include <assert.h> #include <iostream> namespace bit { template<class T> class vector { public: typedef T* iterator; typedef const T* const_iterator; iterator begin() { return _start; } iterator end() { return _finish; } const_iterator begin() const { return _start; } const_iterator end() const { return _finish; } vector() :_start(nullptr) , _finish(nullptr) , _end_of_storage(nullptr) {} //vector(const vector<T>& v) //{ // _start = new T[v.size()]; // v.capacity()也可以 // //memcpy(_start, v._start, sizeof(T)*v.size()); // for (size_t i = 0; i < v.size(); ++i) // { // _start[i] = v._start[i]; // } // _finish = _start + v.size(); // _end_of_storage = _start + v.size(); //} /*vector(const vector<T>& v) :_start(nullptr) , _finish(nullptr) , _end_of_storage(nullptr) { reserve(v.size()); for (const auto& e : v) { push_back(e); } }*/ vector(int n, const T& val = T()) :_start(nullptr) , _finish(nullptr) , _end_of_storage(nullptr) { reserve(n); for (size_t i = 0; i < n; ++i) { push_back(val); } } vector(size_t n, const T& val = T()) :_start(nullptr) , _finish(nullptr) , _end_of_storage(nullptr) { reserve(n); for (size_t i = 0; i < n; ++i) { push_back(val); } } template <class InputIterator> vector(InputIterator first, InputIterator last) :_start(nullptr) , _finish(nullptr) , _end_of_storage(nullptr) { while (first != last) { push_back(*first); ++first; } } 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(const vector<T>& v) :_start(nullptr) , _finish(nullptr) , _end_of_storage(nullptr) { vector<T> tmp(v.begin(), v.end()); swap(tmp); } // v1 = v2 vector<T>& operator=(vector<T> v) { swap(v); return *this; } ~vector() { delete[] _start; _start = _finish = _end_of_storage = nullptr; } size_t capacity() const { return _end_of_storage - _start; } const T& operator[](size_t pos) const { assert(pos < size()); return _start[pos]; } T& operator[](size_t pos) { assert(pos < size()); return _start[pos]; } size_t size() const { return _finish - _start; } void reserve(size_t n) { if (n > capacity()) { size_t sz = size(); T* tmp = new T[n]; if (_start) { //memcpy(tmp, _start, sizeof(T)*sz); for (size_t i = 0; i < sz; ++i) { tmp[i] = _start[i]; } delete[] _start; } _start = tmp; _finish = _start + sz; _end_of_storage = _start + n; } } void resize(size_t n, const T& val = T()) { if (n < size()) { // 缩小容器大小 for (size_t i = n; i < size(); ++i) { _start[i].~T(); // 销毁元素 } _finish = _start + n; } else if (n > size()) { if (n > capacity()) { // 需要重新分配内存 T* new_start = new T[n]; for (size_t i = 0; i < size(); ++i) { new (&new_start[i]) T(std::move(_start[i])); // 移动构造元素 _start[i].~T(); // 销毁原来的元素 } delete[] _start; _start = new_start; _finish = _start + size(); _end_of_storage = _start + n; } // 构造新添加的元素 for (size_t i = size(); i < n; ++i) { new (&_start[i]) T(val); } _finish = _start + n; } // 若 n == size() 则不需要进行任何操作 } void push_back(const T& x) { if (_finish == _end_of_storage) { reserve(capacity() == 0 ? 4 : capacity() * 2); } *_finish = x; ++_finish; //insert(end(), x); } void pop_back() { assert(_finish > _start); --_finish; } iterator insert(iterator pos, const T& x) { assert(pos >= _start); assert(pos <= _finish); if (_finish == _end_of_storage) { size_t len = pos - _start; reserve(capacity() == 0 ? 4 : capacity() * 2); pos = _start + len; } // 挪动数据 iterator end = _finish - 1; while (end >= pos) { *(end + 1) = *end; --end; } *pos = x; ++_finish; return pos; } // stl 规定erase返回删除位置下一个位置迭代器 iterator erase(iterator pos) { assert(pos >= _start); assert(pos < _finish); iterator begin = pos + 1; while (begin < _finish) { *(begin - 1) = *begin; ++begin; } --_finish; return pos; } T& front() { assert(size() > 0); return *_start; } T& back() { assert(size() > 0); return *(_finish - 1); } private: iterator _start; iterator _finish; iterator _end_of_storage; }; }
结语
有兴趣的小伙伴可以关注作者,如果觉得内容不错,请给个一键三连吧,蟹蟹你哟!!!
制作不易,如有不正之处敬请指出
感谢大家的来访,UU们的观看是我坚持下去的动力
在时间的催化剂下,让我们彼此都成为更优秀的人吧!!!