实现一个vector,创建vector对象时构造函数
自己写vector类(push_back、pop_back、erase、insert、clear、empty的完整实现)————定义抽象数据类第十一章Experience _ Blog _vector类方法
自己写vector类(push_back、pop_back、erase、insert、clear、empty的完整实现)————抽象数据类的定义第十一章体验
1目录设计类2实现Vec类2.1类类型2.2数据成员2.3内存分配2.3.1如何分配内存(预分配内存)2.3.2利用库函数实现内存分配2.3.2.1思想2.3.2.2实现2.3.2.2.1库函数准备2.3.2.2类不变量。
2.4成员函数2.4.1构造函数2.4.2析构函数2.4.3复制构造函数2.4.5重载运算符函数2.4.5.1索引运算符函数2.4.5.2赋值运算符2.4.6 push_back成员函数2.4.6 clear成员函数2.4.7 erase成员函数2.4.8 pop_back成员函数2.4.9 emp Ty成员函数2.4.10 insert函数2.4.11赋值函数:2.4.12 print_vec成员函数(不在类中,输出流重写)
完整版本3的示例
1设计一个类当你开始设计一个类的时候,你通常要先确定你想在什么类中提供什么样的接口。确定确切接口的一个方法是研究该类的用户将使用我们编写的类编写什么程序。
因为我们要设计和标准库的向量一样的函数。因此,我们可以模仿使用向量类。
例如,向量可以动态添加元素,索引访问元素,数据成员可以存储不同的内置类型。
2实现Vec类
2.1类的类型因为类中存储了几种不同的数据成员,所以我们使用模板类来实现。
模板类T类Vec{
公共:
//接口
私人:
//实现
}
2.2数据成员因为begin、end、size等函数要在类中实现,所以需要先保存元素的首地址、元素后面的地址和元素个数。
知道这三个数据中的任意两个,就可以引出第三个。为了便于以后内存管理使用指针,这里我们选择只保留第一个地址和数组最后一个元素后面的地址指针,然后计算数组的大小。
在此进一步改进Vec类:
模板类T类Vec{
公共:
//接口
私人:
T*数据;
T*极限;
}使用T类型时,编译器会使用用户在生成Vec时提供的参数,而不是T,这个类型只有在实例化一个Vec的定义时才确定。
2.3内存分配
2.3.1如何分配内存(预分配内存)现在,一个Vec类中添加了一个元素。由于vec类对象中的元素增加1(这里内存大小是固定的,一次只能容纳当前元素),所以需要为对象重新分配新的内存,然后将原内存中的元素复制到当前的新内存中,再构造一个指向新的结束元素的迭代器。
如果频繁添加元素,开销会非常大。
所以会采用一个经典的方法,为程序分配比实际更多的内存,只有当所有预分配的内存都用完了,你才能申请更多的内存。
也就是说,每当需要为类对象分配更多的内存时,我们总是将两倍于当前使用的内存空间分配给类对象。
比如我们创建一个有10个元素的Vec类对象,然后给类对象添加元素(调用push_back函数),这样会分配20个元素的内存空间。它会将现有的10个元素复制到新分配的内存的前一半,并初始化下一个第一个元素空间。
这种预分配要求我们添加元素指针。
原来的“结束指针”指向新分配的内存空间的末尾后面的元素;
另一个新的“最后一个指针”指向构造元素最后一个元素之后的元素(即新分配内存之后访问的第一个元素)。
如下图所示,使用了原来的“限制”和新的“收益”。
在此进一步改进Vec类:
模板类T类Vec{
公共:
//接口
私人:
T*数据;
T * avail//新建
T*极限;
}
2.3.2使用库函数实现内存分配。
2.3.2.1认为,我们可能希望使用newT[n]为Vec分配空间,其中n是要分配的内存量。但是new T[n]不仅分配内存空间,还默认运行T的构造函数初始化每个元素。
如果打算使用new T[n],必须满足以下要求:只有当T有默认构造函数时,才能创建vec t。
这违背了为用户提供尽可能多的灵活性的初衷。
因为在标准的vector类中没有这样的限制,所以我们写的类也希望没有这样的限制。这需要库函数提供的内存分配类。
另外,如果我们要用自己提供的数据初始化Vec类对象的元素,实际上会初始化两次:
一次是new本身,使用T:T()构造函数初始化T类型数组中的每个元素;另一次是将用户提供的数值赋给Vec类型对象的元素。但是如果我们使用之前的预分配方法(分配两倍于我们实际需要的空间),就不需要初始化这些额外的元素(更多分配空间中的元素)。这些空间仅在我们添加新元素时使用(使用push_back函数)。
不,新的,总结起来,有两点:
1为用户提供尽可能多的灵活性的初衷;当使用预先分配的内存时,不需要初始化多重分配空间中的元素。
2.3.2.2实现
2.3.2.2.1库函数准备因为内存的性质太复杂多变,没有必要在语言中固定特性,所以我们用一些C专门设计的支持灵活内存管理的类来管理内存。
例如,计算机内存有很多种。一台计算机可能使用几种不同速度的内存。计算机上的内存可能用于特殊用途,如图形缓冲内存或共享内存,断电后一些内存可能会保留在内存中。由于用户可能希望分配和管理任何类型的内存,因此最好将如何分配和管理内存的工作留给库函数。
标准库不需要支持所有的内存,相反,它提供了一个管理内存的函数,并且具有相同的内存管理接口。
在内存头文件中,提供了一个名为allocator T的类,它可以分配一个旨在存储T型对象但尚未初始化的内存块,并返回一个指向这个内存块中header元素的指针。
这样的指针是非常危险的,因为指针的类型表明它们指向类型对象,但是在这些内存块中并没有存储实际的对象。
分配器的模板功能如下:
模板类T类分配器{
公共:
t * allocate(size _ t);//分配未初始化的内存块
void deallocate(T*,size _ T);//释放未初始化的内存块
void构造(T*,const T);//内存块未初始化以构造单个对象
void destory(T *);//删除参数指向的对象
//.
}其中:cstddef头文件中的size_t类型(无符号整数)表示数组的大小,size_t类型的大小可以安装在任何对象中。
这里,我们只研究与创建Vec类相关的成员函数和非成员函数。
1分配成员函数:用于分配一个指定类型但未初始化的内存块,足够存放对应类型对象的元素。它被称为具有赋值类型的内存块,因为它用于存储T类型的值,并且它的地址可以通过使用T*类型的指针来获得。但是,它没有被初始化,也没有在这个内存块中构造实际的对象。2 deallocate成员函数:用于释放未初始化的内存。它的两个参数是:分配函数的分配指针;另一个是指示在这个内存大小中分配了多少个元素。3构造成员函数:在尚未初始化的内存块区域构造单个对象。它的两个参数是:一个是allocate函数的已分配内存指针;另一个是用来复制到这个内存块的值。4 destory成员函数:删除其参数所指向的T类型的对象。与分配器类相关的非成员函数:
//将一个间隔的值复制到另一个间隔
模板类In,calss For For un initialized _ copy(In,In,For);
//用值填充间隔
模板类,类T
void未初始化_fill(For,For,const T);其中:In是输入迭代器类型,For是正向迭代器类型(顺序读写访问迭代器类型)。因为构造一个新对象不仅仅是为它分配内存,For必须是前向迭代器类型,而不是输出迭代器类型。
这两个函数用于在allocate分配的内存块中构造和初始化一个新对象。
Uninitalized _ copy函数:类似于标准库中的copy函数,用于将前两个参数指针指向的内存块区间内的值复制到第三个参数指针指向的目标内存块。
Uninitialized_fill函数:根据需要构造其第三个参数的尽可能多的副本,以填充前两个参数提供的内存块。
2.3.2.2.2类不变量为了构建一个Vec类型的对象,我们必须始终满足以下四个条件:
1如果对象有元素,数据指向对象数组的第一个元素,否则为零;2;初始化区间中的3个元素;间隔内的4个元素将不会被初始化。这四个条件称为类别不变。一旦一个类对象被创建,类不变条件应该总是成立的。
如果满足四个条件,只要三个成员函数不改变这四个条件,那么这个定律就永远成立。
该类的所有公共成员都不能破坏这个不变量。
2.4成员功能
2.4.1构造函数默认构造函数:
模板类T
void Vec T :create(){
data=avail=limit=0;
} Vec(){ create();}带参数的构造函数:
有两个参数:长度和初始值。
模板类别测试
void Vec T :create(size_type n,const T val){
data=alloc . allocate(n);
limit=avail=data n;
未初始化_fill(data,limit,val);
}explict Vec(size_type n,const T t=T()){
create(n,t);
}复制构造函数:
有两个参数:头指针和尾指针。
模板类T
void Vec T:create(const _ iterator I,const_iterator j){
data=alloc . allocate(j-I);
limit=avail=initialized _ copy(I,j,data);
}Vec(const Vec v){
create(v.begin()、v . end());
}带参数的构造函数:
具有两个迭代器参数的。
模板类T类Vec{
公共:
//带有两个迭代器参数的构造函数
Vec中的模板类(In b,In e){create(b,e);}
私人:
void create中的模板类(在中,在中);
}定义:
模板类T
中的模板类
void Vec T :create(在b中,在e中){
data=alloc . allocate(e-b);
limit=avail=STD:initialized _ copy(b,e,data);
}
2.4.2析构函数:在局部区域创建的对象,如果在它的生存范围之外,就会被自动删除;只有当我们使用delete函数删除动态分配的内存对象时,它才会被删除。
对于Vec类,我们已经在构造函数中为它分配了内存,所以我们必须在析构函数中释放内存。
如果使用默认的析构函数,只会删除对象的指针,但是删除一个指针并不会释放指针对象所占用的内存空间,最后的结果就是内存泄漏。
模板类T
void Vec T :uncreate(){
If(data){//以相反的顺序,删除构造函数生成的元素
迭代器it=avail
而(它!=数据){
alloc . destory(-t);
}
alloc.deallocate(data,limit-data);
}
//重置指针以指示Vec类型对象为空
data=limit=avail=0;
} ~ Vec(){ un create();}
2.4.3复制析构函数(destroyer)当一个类中存在指针成员时,如果指针的值被复制,则被复制对象和被复制对象都指向内存中相同的数据。这将导致任何对象的数据元素的改变影响另一个对象的值。
解决方案是通过值传递将对象作为参数传递,这样复制对象中的操作就不会影响原始对象中的值。
所以有一个复制构造函数:
模板类T类Vec{
公共:
Vec(const Vec c){create(v.begin()、v . end());}
}
重载运算符函数
2.4.5.1索引运算符函数索引运算符在数组中定位正确的元素位置,并返回该元素的引用。通过返回的引用,可以修改存储在Vec类型对象中的数据。
返回类型是引用而不是值,避免在容器很大的时候复制容器中的对象,这样不仅浪费时间,还会影响运行速度。
//读取和写入
t运算符[](size _ type I){返回数据[I];}//必须是成员函数
//只读
const T operator[](size _ type I)const { return data[I];}
2.4.5.2赋值操作者在赋值时应做出自我赋值判断。如果不是自赋值,它会删除原来的对象并释放内存,然后复制新的对象。
如果去掉这个判断,左操作数对象的元素将被删除,它所占用的内存将被释放。同时,右操作数将被删除,因为左操作数和右操作数指向同一个对象。但是要复制正确的操作对象,会带来灾难。
这通常用于判断该关键字仅在成员函数内部有效,并表示指向该函数所操作的对象的指针。例如,在Vec:operator=函数中,它的类型是Vec*。对于二元运算,如赋值运算,它总是指向左操作数。
在赋值操作中,我们以操作数对象的形式返回对表达式的引用调用,其生命周期比赋值操作长,保证了函数在返回时不会被删除。
继续改进Vec类别:
模板类T类Vec{
公共:
//在模板文件的范围内,C允许我们忽略编译器的具体类型名。
Vec运算符=(const Vec);//必须是成员函数
}//实现
//一旦前面指定了我们定义一个Vec类型的成员函数,后面就不需要重用这个属性了。
模板类T
Vec T Vec T:operator=(const Vec RHS){
如果(rhs!=this){//判断字符赋值。
un create();//删除运算符左测试的数组。
create(rhs.begin()、RHS . end());//从右边的元素复制到左边
}
returnn * this
}
2.4.6 push_back成员函数如果当前对象的内存不足以插入新元素,那么就需要重新分配足够的内存,使其能够存储至少两倍的元素。
下面的grow函数就是为了实现这样一个功能。
模板类T void Vec T :grow(){
//扩展对象大小,并分配两倍于对象实际使用的空间。
size _ type new _ size=max(2 *(limit-data),ptrdiff _ t(1));
//分配新的内存空间,并将现有对象元素的内容复制到新内存中。
迭代器new _ data=alloc . allocate(new _ size);
迭代器new _ avail=uninitialized _ copy(data,avail,new_date)
//返回原来的内存空间
un create();
//重置指针以指向新分配的内存空间
data=new _ data
avail=new _ avail
limit=data new _ size
}在新分配的内存空间之后,插入元素。
模板类T
void Vec T:unchecked _ append(const T val){
alloc.construct(avail,val);
}所以push_back函数可以写成:
模板类T
Vec类
公共:
void push_back(const T t){
if(可用==限制)
grow();
unchecked _ append(t);
}
}因为grow函数会产生一个指向未初始化内存空间的avail指针,所以我们在调用grow函数后立即调用unchecked_append函数,使avail指针指向一个有效值。
清除成员函数倒着删除类对象中的值,
模板类T
void Vec T :destory() {
迭代器它=有用
而(它!=数据){
alloc。毁灭(-它);
}
可用性=数据;
}继续完善向量误差修正类:
模板类T
向量误差修正类
公共:
void clear(){
destory();
}
私人:
void destory();
}
擦除成员函数删除单个元素:(判断对象非空以及删除位置有效)
首先删除对象中的元素,然后把该位置后一个的元素值复制到当前未初始化元素的位置,后一个元素值清空,然后这样依次复制直到当前位置等于利益为止,最后重置利益指针。
模板类T
typename Vec T:iterator Vec T:destory(Vec:iterator pos){
如果(数据位置可用性位置=数据){
alloc。销毁(pos);
迭代器it=pos 1;
而(它!=avail){
alloc.construct(pos,* it);
alloc。销毁(pos);
}
avail=pos
}
退货效用;
}删除多个元素:(判断对象非空以及删除区间有效)
首先删除区间内对象中的元素,然后把区间后的元素依次移动到被删除的区间(每次移动后,都删除区间后面对应位置的元素的值)。
模板类T
typename Vec T:iterator Vec T:destory(Vec T:iterator b,Vec T :iterator e) {
if(data b e e e e avail b=data){
迭代器it=b;
而(它!=e){
alloc。毁灭(它);
}
而(e!=avail){
alloc.construct(b,* e);
alloc。销毁(e);
}
avail=b;
}
退货效用;
}继续完善向量误差修正类:
模板类T
向量误差修正类
公共:
无效擦除(迭代位置){
破坏(pos);
}
无效擦除(迭代器b,迭代器e){
destory(b,e);
}
私人:
迭代器毁灭(迭代器);
迭代器毁灭(迭代器,迭代器);
}
弹出_返回成员函数把最后一个进入向量的元素删除:
模板类T
void Vec T :pop() {
如果(数据){
alloc。销毁(-avail);
}
}继续完善向量误差修正类:
模板类T
向量误差修正类
公共:
void pop_back(){
pop();
}
私人:
void pop();
}
空的成员函数为空时返回法斯勒。
模板类T
向量误差修正类
公共:
bool empty() const{return!数据;}
}
插入函数难点在于重新分配内存后、数据、效用、限制的值都会改变,因为重新分配了一块新的内存,因此地址也是新的。结局方法就是记录插入的位置到起始点的距离,这样无论地址怎么改变,只要起始地址加上距离就可以计算出插入点在新内存的地址。
在迭代器的位置插入单个元素
模板类T
void Vec T:add(STD:ptr diff _ T dis,const T val){
如果(无效数据){
迭代器e=效用
迭代器b=avail-1;
而(e!=数据丢失){
alloc.construct(e -,* b-);
alloc。毁灭(b);
}
alloc.construct(data dis,val);
利益
}
}继续完善向量误差修正类:
模板类T
向量误差修正类
公共:
void insert(iterator it,const T t){
STD:ptr diff _ t dis=it-data;
if(avail==limit)grow();
add(dis,t);
}
私人:
void add(std:ptrdiff_t,const T);
}插入区间内的元素
模板类T
void Vec T:add(STD:ptr diff _ T start,Vec T :const_iterator b,Vec T :const_iterator e) {
迭代器位置=数据大小_类型(开始);
if(size _ type(start)size())throw STD:domain _ error( );
Vec T温度;
迭代器insert _ pos=pos
for(;insert_pos!=availinsert_pos) {//原插入位置的后面部分暂存
在…之时push _ back(* insert _ pos);
}
for(const _ iterator it=b;它!=e;它){//覆盖插入元素
* insert _ pos=* it
}
for(const _ iterator it=temp。begin();它!=温度。end();它){//把愿插入位置后面的部分重新插入
* insert _ pos=* it
}
//更新利益
avail=插入_位置
//std:copy(pos,avail,temp);
//std:copy(temp.begin()、temp.end()、std:copy(b,e,pos));
}继续完善向量误差修正类:
模板类T
向量误差修正类
公共:
中的模板类
void insert(iterator out,In b,In e){
STD:ptr diff _ t start=out-data;//插入位置
STD:ptr diff _ t dis=e-b;
if(dis 0){//插入区间合法
const size _ type new _ length=size()size _ type(dis);
size _ type container=limit-data;//容器所有的长度包括未初始化
while(new_length=container){
grow();
container=limit-data;
}
add(start,b,e);
}
}
私人:
void add(std:ptrdiff_t,const_iterator,const _ iterator);
}
分配函数:复制一个迭代器中的内容到向量
模板类T
中的模板类
无效Vec T :assign(在b中,在e中){
un create();
创建(b,e);
}声明:
模板类T类Vec{
公共:
中的模板类
void assign(In,In);
}
打印_vec成员函数(类中没有,重写了输出流)把向量中的元素读到输出流中。
模板类T
ostream Vec T:print _ Vec(STD:ostream OS){
如果(可用性数据0){
const _ iterator iter=data
os * iter
while(iter!=avail){
os * iter
}
OS STD:endl;
}
返回OS;
}继续完善向量误差修正类:
模板类T
向量误差修正类
公共:
STD:ostream print _ vec(STD:ostream);
}
3完整版示例头文件:
#ifndef Vec_H
#定义Vec_H
#包括
#包括
#包括
#包括
模板类T类Vec{
公共:
typedef T*迭代器;
typedef const T * const _ iterator//迭代器
typedef size _ t size _ type//容器长度
typedef T value _ type//值类型
typedef STD:ptr diff _ t difference _ type;//迭代器相减后的结果
typedef T引用;//
typedef常量T常量_引用
//构造函数
vec(){ create();}
//可以显示的给英国压力单位值,也可以使用T的默认构造函数来生成这个值
显式Vec(std:size_t n,const T val=T()){create(n,val);}
//复制构造函数
Vec(const Vec v) { create(v.begin()、v . end());}
//带两个迭代器参数的构造函数
向量误差修正中的模板类(In b,In e){create(b,e);}
//赋值运算符
向量误差修正运算符=(const Vec);//允许忽略具体类型的名称(因此没有显示声明返回类型名称)
//析构函数
~ Vec(){ un create();}
//索引(返回引用,是为了避免容器的对象非常大时对它进行复制)
t运算符[](size_type i) {返回数据[I];}//读写
const T operator[](size _ type I)const { return data[I];}//只读
//动态增加数组
void push_back(const T t){
if(avail==limit){
grow();
}
unchecked _ append(t);
}
//清空
void clear(){
destory();
}
//删除
无效擦除(迭代位置){
破坏(pos);
}
无效擦除(迭代器b,迭代器e){
destory(b,e);
}
//出元素
void pop_back(){
pop();
}
//打印数组
STD:ostream print _ vec(STD:ostream);
//判断空
bool empty() const{return!数据;}
//添加元素:
void insert(iterator it,const T t){
STD:ptr diff _ t dis=it-data;
if(avail==limit)grow();
add(dis,t);
}
中的模板类
void insert(iterator out,In b,In e){
STD:ptr diff _ t start=out-data;//插入位置
STD:ptr diff _ t dis=e-b;
if(dis 0){//插入区间合法
const size _ type new _ length=size()size _ type(dis);
size _ type container=limit-data;
while(new_length=container){
grow();
container=limit-data;
}
add(start,b,e);
}
}
中的模板类
void assign(In,In);
//容器有元素的长度
size _ type size()const { return avail-data;}
//返回迭代器类型
迭代器begin(){返回数据;}//读写
const _ iterator begin()const { return data;}//只读
迭代器end(){ return avail;}
const _ iterator end()const { return avail;}
私人:
迭代器数据;//指针指向向量误差修正的第一个元素
迭代器效用;//指针指向构造元素后面的一个元素
迭代器限制;//指针指向最后一个可获得元素后面的一个元素
//内存分配工具
分配器T alloc//控制内存块分配的对象
//为底层的数组分配空间并对它进行初始化
void create();
void create(size_type,const T);
void create(const_iterator,const _ iterator);
无效创建中的模板类(在中,在中);
//删除数组中的元素并释放其占有的内存
void un create();
//支持推回函数
void grow();
void unchecked _ append(const T);
//支持清楚的函数
void destory();
//支持抹去函数
迭代器毁灭(迭代器);
迭代器毁灭(迭代器,迭代器);
//支持弹出_返回
void pop();
//支持插入
void add(std:ptrdiff_t,const T);
void add(std:ptrdiff_t,const_iterator,const _ iterator);
};
//赋值运算符
模板类T Vec T Vec T:operator=(const Vec RHS){
如果(rhs!=this){//this:指向操作数对象的指针
//删除运算符左侧的数组
un create();
//从右侧复制元素到左侧
create(rhs.begin()、rhs。end());
}
//返回一个指向表达式做操作数对象的一个引用调用
//该对象生存周期大于赋值操作
//保证了函数返回的时候不被删除
返回* this//返回指向的对象
}
//默认构造
模板类T void Vec T :create() {
data=avail=limit=0;
}
//带一个参数大小和给初值
模板类T void Vec T :create(size_type n,const T val){
数据=分配。分配(n);
limit=avail=data n;
STD:initialized _ fill(data,limit,val);
}
//带参数大小
模板类T void Vec T:create(const _ iterator I,const_iterator j){
数据=分配。分配(j-I);
limit=avail=STD:initialized _ copy(I,j,data);
}
模板类T
中的模板类
空Vec T :create(在b中,在e中){
数据=分配。分配(e-b);
limit=avail=STD:initialized _ copy(b,e,data);
}
//删除对象,释放占用的内存
模板类T void Vec T :uncreate(){
//alloc.deallocate函数需要一个非零指针作为参数
//既是它不准备释放任何内存
如果(数据){
//以相反顺序构造函数生成的元素
迭代器它=有用
而(它!=data){//删除对象
alloc。毁灭(-它);
}
//返回占用的所有内存空间
alloc.deallocate(data,limit-data);//删除未初始化内存
}
//重置指针以表明向量误差修正类型对象为空
data=limit=avail=0;
}
//推送_返回函数的成员函数
模板类T void Vec T :grow(){
尺寸类型新尺寸
//扩展对象大小时,为对象分配实际使用的两倍大小的内存空间
//Vec为空的时候,选择一个元素进行分配
new _ size=STD:max(2 *(limit-data),STD:ptrdiff _ t(1));
//分配新的内存空间并将已存在的对象元素内容复制搭配新内存中
迭代器new _ data=alloc分配(new _ size);
迭代器new _ avail=STD:initialized _ copy(data,avail,new _ data);
//返回原来的内存空间
un create();
//重置指针,使其指向新分配的内存空间
数据=新数据
可用性=新可用性
limit=数据新大小
}
//假设利益指向一片新分配的但尚未初始化的内存空间
模板类T void Vec T:unchecked _ append(const T val){
alloc.construct(avail,val);
}
模板类T
void Vec T :destory() {
迭代器它=有用
而(它!=数据){
alloc。毁灭(-它);
}
可用性=数据;
}
模板类T
typename Vec T:iterator Vec T:destory(Vec:iterator pos){
如果(数据位置可用性位置=数据){
alloc。销毁(pos);
迭代器it=pos 1;
而(它!=avail){
alloc.construct(pos,* it);
alloc。销毁(pos);
}
avail=pos
}
退货效用;
}
模板类T
typename Vec T:iterator Vec T:destory(Vec T:iterator b,Vec T :iterator e) {
if(data b e e e e avail b=data){
迭代器it=b;
而(它!=e){
alloc。毁灭(它);
}
而(e!=avail){
alloc.construct(b,* e);
alloc。销毁(e);
}
avail=b;
}
退货效用;
}
模板类T
STD:ostream Vec T:print _ Vec(STD:ostream OS){
如果(可用性数据0){
const _ iterator iter=data
os * iter
while(iter!=avail){
os * iter
}
OS STD:endl;
}
返回OS;
}
模板类T
void Vec T :pop() {
如果(数据){
alloc。销毁(-avail);
}
}
模板类T
void Vec T:add(STD:ptr diff _ T dis,const T val){
如果(无效数据){
迭代器e=效用
迭代器b=avail-1;
而(e!=数据dis){
alloc.construct(e -,* b-);
alloc。毁灭(b);
}
alloc.construct(data dis,val);
利益
}
}
模板类T
void Vec T:add(STD:ptr diff _ T start,Vec T :const_iterator b,Vec T :const_iterator e) {
迭代器位置=数据大小_类型(开始);
if(size _ type(start)size())throw STD:domain _ error( );
Vec T温度;
迭代器insert _ pos=pos
for(;insert_pos!=availinsert_pos) {//原插入位置的后面部分暂存
在…之时push _ back(* insert _ pos);
}
for(const _ iterator it=b;它!=e;它){//覆盖插入元素
* insert _ pos=* it
}
for(const _ iterator it=temp。begin();它!=温度。end();它){//把愿插入位置后面的部分重新插入
* insert _ pos=* it
}
//更新利益
avail=插入_位置
//std:copy(pos,avail,temp);
//std:copy(temp.begin()、temp.end()、std:copy(b,e,pos));
}
模板类T
中的模板类
无效Vec T :assign(在b中,在e中){
un create();
创建(b,e);
}
#endif测试程序:
#包括
#包含" Vec.h "
#包括
使用STD:vector;
使用STD:CIN;使用STD:cout;
使用STD:endl;
int main(int argc,char const *argv[]){
//测构造函数
vec int v;//默认构造
vec int v2(4);//带一个大小参数
Vec int v3(4,6);//带一个大小参数和初值
//cout v3。size()endl;
//for(Vec:size _ type j=0;j!=v3。size();j) {//测索引
//cout v3[j] ;
//}
//测复制构造函数
//v . push _ back(3);//测推回
//v . push _ back(1);
//v . push _ back(10);
//v . push _ back(7);
//隐式复制操作
//int d=max _ Vec(v);//将视觉识别系统作为参数传递给最大真空函数
//cout d;
//Vec v4=sort _ Vec(v);//将排序_向量函数的返回值赋给v4 //初始化
//for(Vec:size _ type j=0;j!=v4。size();j) {
//cout v4[j]" ";
//}
//显示复制
//Vec V5=v3;
//for(Vec:size _ type j=0;j!=V5。size();j) {
//cout V5[j] ;
//}
//赋值
//Vec v4=v;//初始化
//v3=v4;//赋值操作,已存在的值擦去,以新值代替
//for(Vec:size _ type j=0;j!=v3。size();j) {
//cout v3[j] ;
//}
//测删除、清空
//v . push _ back(1);//测推回
//v . push _ back(2);
//v . push _ back(3);
//v . push _ back(4);
五。erase(v . begin());
//v.erase(v.begin(),v . begin()3);
五。pop _ back();
五。clear();
//v . print _ vec(cout);
//for(Vec:const _ iterator it=v . begin();它!=v . end();它){
//cout * it " ";
//}
//测空的
//如果(!v.empty()){
//cout 是
//}其他{
//cout No
//}
//如果(!v3.empty()){
//cout 是
//}其他{
//cout No
//}
//测试插入单个
//v3.insert(v3.begin() 5,10);
//v3。print _ vec(cout);
//测插入区间
v3.insert(v3.begin() 3,10);
Vec int v4(100,66);
v3.insert(v3.begin() 1,v4.begin(),v4。end());
v3。print _ vec(cout);
返回0;
}
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。