当前位置: 首页 > wzjs >正文

关键词免费下载湖南网站seo公司

关键词免费下载,湖南网站seo公司,北京诚信建设网站,网站网站开发文章目录 前言一、vector类的常用接口的模拟实现1.头文件(my vector.h)整体框架2.模拟实现vector类对象的常见构造3.模拟实现vector iterator4.模拟实现vector类对象的容量操作5.模拟实现vector类对象的访问6.模拟实现vector类对象的修改操作 二、vector…

文章目录

  • 前言
  • 一、vector类的常用接口的模拟实现
    • 1.头文件(my vector.h)整体框架
    • 2.模拟实现vector类对象的常见构造
    • 3.模拟实现vector iterator
    • 4.模拟实现vector类对象的容量操作
    • 5.模拟实现vector类对象的访问
    • 6.模拟实现vector类对象的修改操作
  • 二、vector 迭代器失效问题


前言

vector类的常用接口的模拟实现 以及 vector 迭代器失效问题。配套博客: 【C++】vector(上):vector的常用接口介绍


一、vector类的常用接口的模拟实现

1.头文件(my vector.h)整体框架

#include <algorithm>
#include <assert.h>
namespace zh
{template<class T>class vector{public:// Vector的迭代器可以直接用指针封装typedef T* iterator;typedef const T* const_iterator;// construct and destroy //vector();vector(int n, const T& value = T());template<class InputIterator>vector(InputIterator first, InputIterator last);vector(const vector<T>& v);vector<T>& operator= (vector<T> v); // 赋值运算符重载~vector(); // 析构函数// iterator //iterator begin();iterator end();const_iterator begin() const;const_iterator end() const;// capacity //size_t size() const;size_t capacity() const;void reserve(size_t n);void resize(size_t n, const T& value = T());// access //T& operator[](size_t pos);const T& operator[](size_t pos)const;// modify //void push_back(const T& x);void pop_back();iterator insert(iterator pos, const T& x);iterator erase(iterator pos);void swap(vector<T>& v);private:iterator _start = nullptr; // 指向有效数据的开始iterator _finish = nullptr; // 指向有效数据的尾部iterator _end_storage = nullptr; // 指向存储容量的尾部};
}

2.模拟实现vector类对象的常见构造

template<class T>
class vector
{
public:vector() // 默认构造函数{}vector(int n, const T& value = T()) // 构造并初始化n个val{_start = new T[n];_finish = _end_storage = _start + n;while (n--){_start[n] = value;}}template<class InputIterator>vector(InputIterator first, InputIterator last) // 使用迭代器进行初始化构造{auto it = first;while (it != last){push_back(*it++);}}vector(const vector<T>& v) // 拷贝构造{if (v._start != nullptr){_start = new T[v.capacity()];_finish = _start + v.size();_end_storage = _start + v.capacity();auto it1 = begin();auto it2 = v.begin();while (it2 != v.end()){*it1++ = *it2++;}}}vector<T>& operator= (vector<T> v) // 赋值运算符重载{swap(v);return *this;}~vector() // 析构函数{if (_start != nullptr){delete[] _start;_start = _finish = _end_storage = nullptr;}}
private:iterator _start = nullptr; // 指向有效数据的开始iterator _finish = nullptr; // 指向有效数据的尾部iterator _end_storage = nullptr; // 指向存储容量的尾部
};

3.模拟实现vector iterator

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;}
private:iterator _start = nullptr; // 指向有效数据的开始iterator _finish = nullptr; // 指向有效数据的尾部iterator _end_storage = nullptr; // 指向存储容量的尾部
};

4.模拟实现vector类对象的容量操作

template<class T>
class vector
{
public:size_t size() const{return _finish - _start;}size_t capacity() const{return _end_storage - _start;}void reserve(size_t n){if (n > capacity()){iterator tmp = new T[n];auto it = _start;int i = 0;while (it != _finish){tmp[i++] = *it;it++;}delete[] _start;_start = tmp;_finish = tmp + i;_end_storage = tmp + n;}}void resize(size_t n, const T& value = T()){if (n <= size()){_finish -= size() - n;}else{if (n > capacity()){size_t newcap = 2 * capacity();if (n > newcap)newcap = n;reserve(newcap);}size_t i = size();_finish += n - size();while (i < size()){_start[i++] = value;}}}
private:iterator _start = nullptr; // 指向有效数据的开始iterator _finish = nullptr; // 指向有效数据的尾部iterator _end_storage = nullptr; // 指向存储容量的尾部
};

5.模拟实现vector类对象的访问

template<class T>
class vector
{
public: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 = nullptr; // 指向有效数据的开始iterator _finish = nullptr; // 指向有效数据的尾部iterator _end_storage = nullptr; // 指向存储容量的尾部
};

6.模拟实现vector类对象的修改操作

template<class T>
class vector
{
public:void push_back(const T& x) // 在末尾插入一个元素{if (size() == capacity()){size_t n = capacity() == 0 ? 4 : 2 * capacity();reserve(n);}_start[size()] = x;_finish++;}void pop_back() // 删除末尾元素{assert(size() > 0);_finish--;}iterator insert(iterator pos, const T& x) // 在迭代器 pos 位置插入元素 x{assert(pos >= _start && pos <= _finish);if (size() == capacity()){size_t newcap = capacity() == 0 ? 4 : 2 * capacity();size_t n = pos - _start;reserve(newcap);pos = _start + n;}auto it = _finish;while (pos < it){*it = *(it - 1);it--;}*pos = x;_finish++;return pos;}iterator erase(iterator pos) // 删除迭代器 pos 指向的元素{assert(pos >= _start && pos < _finish);auto it = pos;while (it < _finish - 1){*it = *(it + 1);it++;}_finish--;return pos;}void swap(vector<T>& v) // 交换两个vector对象的内容{std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_storage, v._end_storage);}
private:iterator _start = nullptr; // 指向有效数据的开始iterator _finish = nullptr; // 指向有效数据的尾部iterator _end_storage = nullptr; // 指向存储容量的尾部
};

二、vector 迭代器失效问题

迭代器的主要作用就是让算法能够不用关心底层数据结构,其底层实际就是一个指针,或者是对指针进行了封装,比如:vector的迭代器就可以使用原生态指针T* 。因此迭代器失效,实际是指 vector 进行某些修改操作后,原有的迭代器(或指针、引用)指向的内存地址可能变得无效,继续使用这些迭代器会导致未定义行为(如程序崩溃、数据错误)。 比如:迭代器底层对应指针所指向的空间被销毁了(扩容等行为导致底层空间改变),而使用一块已经被释放的空间,造成的后果是程序崩溃(即如果继续使用已经失效的迭代器,程序可能会崩溃)。

对于vector可能会导致其迭代器失效的操作有:

  1. 会引起其底层空间改变的操作(插入、赋值 和 修改容量),都有可能会导致迭代器失效,比如:resize、push_back、insert、assign 和 reserve等。
#include <iostream>
#include <vector>
using namespace std;
int main()
{vector<int> v{ 1,2,3,4,5,6 }; // 由调试结果(下图)可知:size == capacity = 6auto it = v.begin();// 头插一个元素,因为size == capacity,所以该操作会引起扩容v.insert(v.begin(), 0);// resize的作用是增加有效元素个数,操作期间可能会引起扩容// v.resize(50, 8);// reserve的作用是扩充容量但不改变有效元素个数,操作期间可能会引起扩容// v.reserve(50);// 插入元素期间,可能会引起扩容,而导致原空间被释放// v.push_back(8);// 给vector重新赋值,可能会引起扩容// v.assign(50, 8);while (it != v.end()){cout << *it << " ";++it;} cout << endl;return 0;
}

在这里插入图片描述
在这里插入图片描述
出错原因:以上操作,都有可能会导致vector扩容,也就是说vector底层原理旧空间被释放掉,而在打印时,it还使用的是释放之间的旧空间,在对it迭代器操作时,实际操作的是一块已经被释放的空间,而引起代码运行时崩溃。

解决方式:在以上操作完成之后,如果想要继续通过迭代器操作vector中的元素,只需给it重新赋值即可。
如下:

#include <iostream>
#include <vector>
using namespace std;
int main()
{vector<int> v{ 1,2,3,4,5,6 };auto it = v.begin();// insert的返回值:若插入单个元素,返回值指向新插入的该元素;//                若插入多个元素或区间,则指向第一个新插入的元素。it = v.insert(v.begin(), 0);// 即使插入导致内存重新分配,返回的迭代器仍有效(直接指向新内存位置)。while (it != v.end()){cout << *it << " ";++it;} cout << endl;return 0;
}

在这里插入图片描述

  1. 指定位置元素的删除操作(erase)

示例一(erase删除元素后,被删除位置之后的迭代器失效(元素前移)):

#include <iostream>
#include <vector>
using namespace std;
int main()
{vector<int> v = { 10, 20, 30, 40 };auto it = v.begin(); // 指向10auto it1 = v.begin() + 1;  // 指向20auto it2 = v.begin() + 2;  // 指向30v.erase(it1);  // 删除20,vector变为{10,30,40}cout << *it2; // 删除元素后,被删除位置之后的迭代器失效(元素前移)return 0;
}

在这里插入图片描述

示例二(删除元素后,被删除位置的迭代器也失效(元素前移)):

int main()
{vector<int> v = { 10, 20, 30, 40 };auto it = v.begin(); // 指向10auto it1 = v.begin() + 1;  // 指向20auto it2 = v.begin() + 2;  // 指向30v.erase(it1);  // 删除20,vector变为{10,30,40}cout << *it1; // 删除元素后,被删除位置的迭代器也失效(元素前移)return 0;
}

在这里插入图片描述
解决方式:在以上操作完成之后,如果想要继续通过迭代器it1操作vector中的元素,只需给it1重新赋值即可,如下:

int main()
{vector<int> v = { 10, 20, 30, 40 };auto it = v.begin(); // 指向10auto it1 = v.begin() + 1;  // 指向20auto it2 = v.begin() + 2;  // 指向30// erase的返回值是指向被删除元素之后第一个有效元素的迭代器// 删除元素后,被删元素及其之后的所有迭代器都会失效,但返回值是新的有效迭代器it1 = v.erase(it1);  // 删除20,vector变为{10,30,40}cout << *it1;return 0;
}

在这里插入图片描述

示例三(删除元素后,被删除位置之前的迭代器能正常使用):

int main()
{vector<int> v = { 10, 20, 30, 40 };auto it = v.begin(); // 指向10auto it1 = v.begin() + 1;  // 指向20auto it2 = v.begin() + 2;  // 指向30v.erase(it1);  // 删除20,vector变为{10,30,40}cout << *it; // 删除元素后,被删除位置之前的迭代器能正常使用return 0;
}

在这里插入图片描述

一、导致迭代器失效的典型场景总结

  1. 插入元素(push_back, insertresize等)

    • 当插入导致vector容量不足时,会重新分配内存,所有迭代器、指针、引用都会失效
    • 即使容量足够,插入位置及其之后的迭代器也会失效(元素被后移)。
  2. 扩充容量(reserve等) 和 重新赋值(assign等)

    • 任何导致内存重新分配的操作都会使所有迭代器失效
  3. 删除元素(erase, pop_back等)

    • 被删除元素及其之后的所有迭代器、指针、引用会失效(元素前移)
    • 被删除元素之前的迭代器、指针、引用仍然保持有效

二、如何减少迭代器失效?

  1. 插入/删除后更新迭代器
    • eraseinsert会返回新的有效迭代器:
vector<int> v{ 1,2,3,4,5,6 }; 	
auto it = v.begin(); 	
it = v.insert(v.begin(), 0); // 使用返回的新迭代器 	
it = v.erase(it); // 使用返回的新迭代器  
  1. 预留足够容量
    • 使用reserve()预先分配足够内存,减少重新分配次数:
std::vector<int> v;    
v.reserve(100);  // 预分配足够内存空间   
  1. 避免保存旧迭代器
    • 修改操作后,不要继续使用旧的迭代器、指针或引用。

总结表格

操作类型失效范围解决方案
插入导致扩容所有迭代器重新获取所有迭代器
插入未扩容插入位置及其之后的迭代器更新插入位置后的迭代器
reserve扩容 和 用assign重新赋值所有迭代器重新获取所有迭代器
删除元素被删位置及其之后的迭代器使用erase返回的新迭代器

http://www.dtcms.com/wzjs/102817.html

相关文章:

  • 客户问 你们网站怎么做的网站怎么快速收录
  • 用什么网站可以做代运营公司怎么找客户
  • 网站关键词 价格生成推广一般收多少钱
  • 想美团这样的网站怎么做网站维护主要做什么
  • 网站自动登录怎么做在线注册网站
  • 长沙口碑好的做网站公司哪家好网站seo分析报告
  • 固始网站建设正规淘宝代运营去哪里找
  • 平面设计官方网站知名网站排名
  • 广元企业网站建设美国搜索引擎排名
  • 做网站是干什么用的2019网站seo
  • 网站建设技术公司企业网站制作费用
  • 富锦建设局网站排名首页服务热线
  • 广广东网站建设seo首页网站
  • 做网站需要的资质站长工具视频
  • 影视自助建站官网人民网今日头条
  • 上杭县城乡规划建设局网站如何创建网站站点
  • 珠海移动网站设计上海还能推seo吗
  • 建设通相似网站北京全网推广
  • wordpress中触发鼠标按钮事件动态动态代码代码百度搜索名字排名优化
  • 建立网站分为几阶段市场营销方案怎么做
  • wordpress 仿值得买seo岗位工作内容
  • 外贸建立网站怎么做推广网站免费
  • 网站建设类行业资讯如何做好网络营销工作
  • 广州做外贸网站公司岳阳网站建设推广
  • 如何查网站的外链seo推广招聘
  • 网站建设制作要学什么北京做网站的公司有哪些
  • 做网站后端需要掌握什么技术抖音代运营收费详细价格
  • 凯里做网站it培训学校
  • WordPress图片生成文章图片优化软件
  • 评论回复网站怎么做的百度指数查询官网大数据