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

做网站如何购买服务器如何做好宣传推广

做网站如何购买服务器,如何做好宣传推广,图书宣传推广方案,下列属于b2b网站的有文章目录 vector的模拟实现构造函数析构函数迭代器容量sizecapacityreverse 遍历下标[] 修改push_backpop_backinsert 结语 我们大家有又见面了&#xff0c;给生活加点</font color red>impetus&#xff01;&#xff01;开启今天的编程之路 今天我们来学习vector。了解一…

文章目录

  • vector的模拟实现
    • 构造函数
    • 析构函数
    • 迭代器
    • 容量
      • size
      • capacity
      • reverse
    • 遍历
      • 下标+[]
    • 修改
      • push_back
      • pop_back
      • insert
    • 结语

我们大家有又见面了,给生活加点</font color =red>impetus!!开启今天的编程之路
在这里插入图片描述
今天我们来学习vector。了解一些基本的接口已经迭代器失效问题!!
作者:٩( ‘ω’ )و260
我的专栏:C++初阶,数据结构初阶,题海探骊,c语言
感谢点赞,关注!!

vector的模拟实现

在 C++ 里,std::vector 属于标准模板库(STL)中的容器,它可看作是动态数组。话多多说,直接进入模拟实现。
首先我们先要明白,vectoe底层是数组,如果我们数组中存储的是字符类型,那还要string类干嘛:

1:string后面默认有\0,vector没有
2:接口有较大差异,比如vector中其实没有find函数,只能使用算法库中的函数

其次就是需要定义vector的结构,也许你会认为可以使用顺序表定义的结构,但是在这里,我们为了更加接触底层,在vector的源代码中,他的成员函数是这样定义的:总共有三个,分别为迭代器,名称为:_start,_finish,_end_of_storage。分别代表的是有效位置的第一个元素,有效位置的最后一个元素,有效空间的最后一个位置
我们来看下面的定义:

class vector{
pubilc:
private:iterator _start;iterator _finish;iterator _end_of_storage;
};

其实这样还是会有一点小瑕疵,编译器怎么知道iterator是什么东西吗?
而且,vector的底层是数组,那么数组应该是可以存储各式各样的数据类型,包括整形,浮点数,自定义类型等等,我们再来加以修改一下:

template<class T>
class vector{
pubilc:typedef T* iterator;//定义普通迭代器typedef const T* const_iterator;//定义const迭代器
private:iterator _start;iterator _finish;iterator _end_of_storage;
}

作用:指向各种数据的迭代器。

因为vector的底层是数组,所以这里的迭代器就可以理解为数组的指针,本质上是因为数组空间是连续的。在这里,我们需要重点学习迭代器失效!!
这里的迭代器的typedef一定要定义在public中,这样外面才能使用。
随后我想补充自己总结的知识点:
1:模版可以做声明和定义分离,但是不要分离到两个文件,否则会发生链接错误
2:利用模版传参一般是传引用,因为是数组,值传递的时候调用拷贝构造,目的是防止深拷贝
3:注意,只有先声明模版,函数才能够传递模版参数,例如

//template<class T>
//void Print(const Mrzeng::vector<T>&res){}

构造函数

在这里我们主要实现是三种构造函数,第一种是无参构造,第二种是有参构造,第三种是利用其他类来进行构造
先来看第一种
因为是无参的构造函数,所以我们构造函数的时候必须要去初始化列表中初始化,但是由于这些都是迭代器可以理解为指针,所以我们直接将三者的初始化为空指针:

vector
:_start(nullptr),_finish(nullptr),_end_of_storage(nullptr)
{}

接下来我们来完成有参的初始化,但是这里的结果是数组中的数据全部都是相同的,因为这种构造就是用n个val值来初始化vector实例化的对象
直接来看代码:

vector(size_t n,const T& val=T())//匿名对象
{assert(n>0);reverse(n);for(size_t i=0;i<n;i++){	push_back(val);}
}

虽然说我们还没有实现迭代器以后push_back,但是这个大致思路确实是如此。
首先第一句代码使用了匿名对象:因为外部传给vector的值并不确定,所以vector中有可能能够存储各式各样的值,我们这里只能够使用匿名对象。
匿名对象首先会调用的构造函数,去构造一个自定义类型之后就会传递给vector,那么,有的同学会问,那内置类型怎么办呢?难道内置类型使用匿名对象时会升级为自定义类型
答案确实是如此,接下来利用代码验证:
在这里插入图片描述
接下来实现第三种,使用另一个模版来构造vector,鉴于我们对于后面还没学习,这里主要讲解用法,来看代码:

vector(initializer_list<T> il)
{reverse(il.size());for(auto& e:il){push_back(e);}
}

initializer_list是另一类,在这里初始化的时候可以使用任何数据来进行初始化,比如:

vector<int> v1{1,2,3,4,5};

在这里的原理是什么呢?

利用initializer_list初始化时自动开空间,自动生成首尾迭代器,这也是为什么我我没有显示写begin(),end(),但是也能够使用范围for。注意范围for的本质就是迭代器

析构函数

析构函数简单,只需要释放开辟的空间即可,来看下列代码:

~vector()
{if(_start){delete[]_start;_start=_finish=_end_of_storage=nullptr;}
}

这里只需要判断是否需要析构即可,因为一开始无参初始化三个成员变量都是空,再来析构的话就显得画蛇添足了!!

迭代器

这里实现开始与结束的迭代器,与string类相差无几,直接来看代码:

iterator begin()
{return _start;
}
iterator end()
{return _finish;
}
const_itreator begin()const
{	return _start;
}
const_iterator end()const
{return _finish;
}

在迭代器这里有一个细节:

迭代器是左闭右开的类型,类似于[begin(),end()),末尾迭代器并不是包含在内的元素,这里需要记忆

容量

size

size其实就是有效位置的最后迭代器减上有效位置的起始迭代器即可:

size_t size()const
{return _finish-_start;
}

可以理解为指针:两个指针相减的值就是其中相邻元素的个数,前提是指向同一块空间

capacity

capacity就是容量的最后位置迭代器减上有效位置起始迭代器:

size_t capacity()const
{return _end_of_capacity-_start;
}

可以理解为指针:两个指针相减的值就是其中相邻元素的个数,前提是指向同一块空间

reverse

需要判断什么时候需要扩容,扩容之后又要做什么,代码是否有错误?而在扩容之中我们又需要干什么?
来看下列代码:

void reverse(size_t n)
{if(n>_end_of_storage){T*tmp=new T[n];memcpy(tmp,_start,size()*sizeof(T));//注意memcpy的单位是字节delete[]_start;_start=tmp;//修改成员变量_finish=tmp+size();_end_of_capacity=tmp+n;}
}

这里在_finish和_end_of_storage修改成员变量的时候主要是为了标记这个迭代器是在哪个vector之中的!!
那么我们上面还有没有可以优化的地方呢?上面的代码有没有问题呢?我们来看一下:

首先我们看一下倒数第二行的size,计算是通过_finish-_start实现的,但是我们发现,在求size之前我们就已经对_start进行了变化,此时_finish指向旧的已经被销毁的空间,_start指向新空间的起始位置,此时代码肯定报错:

在这里插入图片描述
再来看这张图理解,所以如果按照这个代码扩容的话,_finish的结果会一直是0。
在这里插入图片描述
最终代码:

void reverse(size_t n)
{if(n>_end_of_storage){size_t old_size=size();//存储下来这个偏移量T*tmp=new T[n];if(_start)//如果被拷贝数据此时不是空的话,我再来进行操作,否则就不需要操作了{memcpy(tmp,_start,old_size*sizeof(T));delete[]_start;}_start=tmp;//修改成员变量_finish=tmp+old+size();_end_of_capacity=tmp+n;}
}

遍历

下标+[]

此时与string相差无几,直接来看代码即可:

T& operator[](size_t pos)
{assert(pos < size());return _start[pos];
}

修改

push_back

尾插,首先我们需要先判断是否需要扩容,随后再来进行尾插,最后再对成员变量进行修改:
来看代码:

void push_back(const T&x)
{if(_finish==_end_of_storage){size_t newcapacity=_end_of_storage==0?4:2*capacity();reverse(newcapacity);}*_finish=x;_finish++;
}

pop_back

对尾部进行删除,删除之后修改成员变量

void pop_back()
{_finish--;
}

直接让有效元素减一个就可以了

insert

我们需要在指定位置进行插入操作,首先需要先检查是否需要扩容,随后再来移动元素,最后再插入数据以及修改成员变量。
来看代码:

void insert(iterator pos,const T&x)
{if(_finish==_end_of_storage){size_t newcapacity=_end_of_storage==0?4:2*capacity();reverse(newcapacity);}iterator it=_finish-1;while(it>=pos){*(it+1)=*it;it--;}*pos=x;_finish++;
}

这样的代码看起来是ok的,但是如果我们去检验,我们会发现一个问题,此时我们会发现我们一直无法退出循环,那这个是什么原因呢?迭代器失效–原因是野指针

我们如果发生了扩容,就会导致旧空间销毁,但是最开始pos迭代器肯定是指向旧空间的,开辟新空间之后pos迭代器变成就是野指针了,所以我们应该及时对pos迭代器进行修改

所以我们这里应该改为:

	if(_finish==_end_of_storage){int len=pos-_start;//记录下偏移量size_t newcapacity=_end_of_storage==0?4:2*capacity();reverse(newcapacity);//利用偏移量找到新的pos迭代器pos=_start+len;//前面加一个_start主要是为了标记新的数组的偏移量}

来看下面图解:
在这里插入图片描述
这里还有一个细节:

如果我们在外面设置了pos指针,插入数据之后一定不要再去使用这个迭代器,因为我不知道是否会产生扩容,不知道这个迭代器是否会被更新,因为我这里是使用的传值调用,里面的操作不会影响外面,里面这个迭代器经历了什么我是一点都不知道的。
那你可能会说,那我们转引用不就好了吗?但是如果是一个迭代器再来进行算术加减法,就会产生一个临时对象记录这个结果,传过去临时对象,不加const的话又是一个权限放大问题,所以我们必须加上const,但是加上const我的pos位置的数据就不能再修改了!!
所以:为了方便,不要在使用调用insert实参为迭代器的变量了!!

示例代码:

	int x = 2;cin >> x;auto pos = find(v.begin(), v.end(), x);if (p != v.end()){v.insert(pos, x * 10);// insert以后pos不能使用,pos可能失效,不要访问这个迭代器// cout << *pos << endl;}

find是算法库中的函数,如果找到对应位置数值为x的位置,就会放回这个位置的迭代器,,否则会返回last位置的迭代器,代表没有找到。
在这里插入图片描述

结语

感谢大家阅读我的博客,不足之处欢迎与我交流讨论。
时人不识凌云木,直待凌云始道高!!加油!!
在这里插入图片描述

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

相关文章:

  • 杭州如何做百度的网站semester是什么意思
  • 做网站好的公司有哪些网络营销的概念和含义
  • 大连做网站的网络公司搜索引擎营销特点是什么
  • 医院客户做网站找谁搭建网站平台需要多少钱
  • 想花钱做网站怎么做seo高级优化技巧
  • 郑州那家做网站便宜常州seo建站
  • 重庆专业的网站建设影视站seo教程
  • 做的网站为什么图片看不了百度竞价推广方案范文
  • 嵌入式软件开发怎么学网站关键词排名优化方法
  • 贵阳市小程序网站开发公司公众号代运营
  • 上海企业服务云官网沈阳seo网站推广
  • 微信显示个人网站企业网站有哪些
  • wordpress中文表单生成seo站长工具综合查询
  • 省级建设网站关键词统计工具有哪些
  • 软文发布平台哪家好google关键词优化
  • 西部网站管理助手4.0百度快照投诉中心
  • 河南那家做网站实力强互联网营销专业
  • 如何自己做网站知识宁波网站优化公司电话
  • 如何自己做优惠券网站湖北网站seo设计
  • axture做网站站长资源平台
  • 网站建设在线视频卡顿sem竞价推广是什么
  • 洛阳网站建设价格百度百度一下你就知道主页
  • 英语网站的栏目名称营销案例100例小故事及感悟
  • 化工企业网站jsp培训机构网站
  • 马鞍山网站制作互联网域名注册查询
  • 做模板网站镇江seo优化
  • 广州知名网站设计网络精准营销推广
  • 人民日报客户端我爱红旗推动防控措施持续优化
  • 麻涌东莞网站建设市场营销推广方案模板
  • 门户网站建设工作汇报网络推广渠道都有哪些