c++ vector 简单实现。
第二次修改:
1)熟悉基本的模板编程,头文件和定义必须放到一起。
2)熟悉内存管理模板类 allocator<T>。
1.使用标准库的内存管理类 allocator<T> 代替原来c的malloc和free。 可以给无默认构造函数的类分配指定空间。
2.第一次写的时候,只free vectore元素占用内存, 没有调用元素的析构函数,那个时候还没有搞清楚,析构什么时候会调用。free 是无法调用析构函数的。
3.模板类的编译问题: 因为是模板类,有类型参数,类的方法编译的时候,不能确定所占用的栈大小.必须使用的时候才能确定,而且不同的T类型,有不同的方法地址.所以申明定义放到一起
4.myalloc.destroy(pb);//仅仅调用析构函数.
5)void *memset(void *s, int ch, size_t n);
函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
#ifndef MYVECTOR_H_INCLUDED #define MYVECTOR_H_INCLUDED //allocator<T> a; 定义一个T类型的allocator对象。 //a.allocate(n); 申请n个T大小的,未分配的空间。类似(T*) malloc(sizeof(T)*n) //a.deallocate(p,n) 释放内存,p为T*,n为释放的T类型对象的数量。注意:T类型对象本身,如有需要释放的资源,必须先释放,a.deallocate(p,n)只是释放对象本身的内存,而对象的建立又额外申请的资源,需要另外处理。 //a.construct(p,t) 复制构造,用t来复制构造。相当于 new (p) T(t),这个是placement new的用法 new(place_address) type(initializer-list)
//a.destroy(p) 调用pd对象的析构函数。 //uninitialized_copy(startit,endit,it) startit,endit :要复制的开始迭代器地址和结束地址。it:要复制的迭代器地址。 //uninitialized_fill(startit,endit,obj) startit,endit :要复制的开始迭代器地址和结束地址。it:要复制的对象。 使用复制构造函数填充内存 //uninitialized_fill_n(startit,endit,obj,n) startit,endit :要复制的开始迭代器地址和结束地址。it:要复制的对象。 n,要复制的数量。 使用复制构造函数填充内存 //因为是模板,有类型参数,类的方法编译的时候,不能确定所占用的栈大小.必须使用的时候才能确定,而且不同的T类型,有不同的方法地址.所以申明定义放到一起 #include <memory> #include <stdexcept> #include <iostream> using namespace std; template<typename T> class myVector{ public: //如果分配错误呢? myVector():pbegin(myalloc.allocate(defautlSize)),pend(pbegin),pcapcity(pbegin+defautlSize),Vsize(0),Vcapcity(defautlSize){} void push_back(const T& _obj) { if(pend>=pcapcity) { T* pTempAlloc=myalloc.allocate(Vcapcity*2); T* pPrep=pbegin; if(pTempAlloc!=0) { uninitialized_copy(pbegin,pend,pTempAlloc); pbegin=pTempAlloc; pend=pbegin+Vsize; pcapcity=pbegin+(Vcapcity*2); Vsize=Vsize; Vcapcity+=Vcapcity; //清理原资源. destroyS(pPrep,pPrep+Vsize,pPrep+Vsize); } else { throw runtime_error("error allocator!"); } } myalloc.construct(pend,_obj); ++pend; ++Vsize; } void erase(unsigned int index) { if(index>=0&& index<Vsize) { myalloc.destroy(pbegin+index);//手动调用对象析构 for(int i=index+1;i!=Vsize;++i)//往前覆盖.最后一个对象占用的内存,不管了.pend往前移动就好. { uninitialized_copy(pbegin+i,pbegin+i+1,pbegin+i-1); } --Vsize; --pend; } else { throw runtime_error("index over range."); } } ~myVector() { destroyS(pbegin,pend,pcapcity); } myVector(const myVector& _obj) { pbegin=myalloc.allocate(_obj.Vcapcity); pend=pbegin+_obj.Vsize; pcapcity=pbegin+_obj.Vcapcity; Vsize=_obj.Vsize; Vcapcity=_obj.Vcapcity; uninitialized_copy(_obj.pbegin,_obj.pend,pbegin); } myVector& operator=(const myVector& _obj) { if(&_obj!=this) { destroyS(pbegin,pend,pcapcity); pbegin=myalloc.allocate(_obj.Vcapcity); pend=pbegin+_obj.Vsize; pcapcity=pbegin+_obj.Vcapcity; Vsize=_obj.Vsize; Vcapcity=_obj.Vcapcity; uninitialized_copy(_obj.pbegin,_obj.pend,pbegin); } return *this; } int size() { return pend-pbegin; } int capcity() { return pcapcity-pbegin; } void showInfo() { cout<<"pbegin:"<<(void *)pbegin<<". size:"<<Vsize<<". capcity"<<Vcapcity<<". pend:"<<(void *)pend<<endl; T* pb=pbegin; for(pb;pb!=pend;++pb) { cout<<*pb<<endl; } } private: static allocator<T> myalloc; const static int defautlSize=3; T* pbegin; T* pend; T* pcapcity; unsigned int Vcapcity; unsigned int Vsize; void destroyS(T* PS,T* PE,T* PC) { T* pb=PS; for(pb;pb!=PE;++pb) { myalloc.destroy(pb);//仅仅调用析构函数. } myalloc.deallocate(PS,PC-PS); } }; //int book::pid=6 template<typename T> allocator<T> myVector<T>::myalloc=allocator<T>(); #endif // MYVECTOR_H_INCLUDED
实现功能基本:
插入元素,pushback.
引用构造,
copy功能.
按索引返回.
删除索引位置元素.
备注:
//默认大小为32个数据元素。新插入不够,空间翻倍,为32,64,128。。。。
//引用构造,新对象和引用对象一致。 copy复制,先检测空间,若空间不够,调整为右直的大小。
//注意capcity 的const。是为了MyVector2(const MyVector2<T>&);
有几个新知识点:
1)placement new 的写法 。给 一个已经申请内存的空间。放入对象值。new是先申请后放入。这里省去申请。
new(endP) T(*s_iterator);//placement new .
2)int类型的数据与unsigned int类型的数据进行比较时会把int类型的数据转换为unsigned int 类型的数据,然后再进行比较。
所以 int -1会大于 unsigned 0.
3)pushback 中。空间 不够 。要申请空间。注意不要建立临时对象,再吧临时对象的数据给左值。 因为临时对象离开pushback韩素 会析构。导致左值的结果被删除了。
测试发现有问题的同学,这里看看自己有没有犯同样的错误。
所以直接申请空间。再把地址给左值就好了。
myvector2.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | #ifndef MYVECTOR2_H_INCLUDED #define MYVECTOR2_H_INCLUDED #include "malloc.h" #include <iostream> using namespace std; //实现功能基本:插入元素,pushback. //引用构造, //copy功能. //按索引返回. //删除索引位置元素. //默认大小为32个数据元素。新插入不够,空间翻倍,为32,64,128。。。。 //引用构造,新对象和引用对象一致。 copy复制,先检测空间,若空间不够,调整为右直的大小。 //注意capcity 的const。是为了MyVector2(const MyVector2<T>&); template < typename T> class MyVector2{ public : MyVector2(); MyVector2( const MyVector2<T>&); MyVector2<T> & operator=( const MyVector2<T>&); //copy操作,左直是一定存在的。所以可以返回引用。 int PushBack( const T&); T& operator[](unsigned int ); unsigned int size() const ; unsigned int capcity() const ; //注意capcity 的const。是为了MyVector2(const MyVector2<T>&);中,参数是const.而且还调用了参数的capcity()方法.所以方法必须const. void erace(unsigned int ); ~MyVector2() { del(); } private : T* firstP; T* endP; T* CapicityP; static const unsigned int stepsize=32; void addEnd(); void del(); MyVector2(unsigned int ); //private 指定模板数据类型数量来初始化类. }; template < typename T> MyVector2<T>::MyVector2():firstP((T*) malloc ( sizeof (T)*stepsize)),endP(firstP) { CapicityP=firstP+stepsize; //不知为什么,如果防入初始化.CapicityP是莫名的数据. cout<< "c malloc:" <<firstP<<endl; } template < typename T> MyVector2<T>::MyVector2( const MyVector2<T>& _rhs):firstP((T*) malloc ( sizeof (T)*_rhs.capcity())),endP(firstP) { cout<< "ref malloc:" <<firstP<<endl; CapicityP=firstP+_rhs.capcity(); T* s_iterator=_rhs.firstP; for (s_iterator;s_iterator!=_rhs.endP;++s_iterator) { new (endP) T(*s_iterator); //placement new . ++endP; } } template < typename T> MyVector2<T> & MyVector2<T>::operator=( const MyVector2<T>& _rhs) { if ( this ->capcity()>=_rhs.size()) { this ->endP= this ->firstP; T* s_iterator=_rhs.firstP; for (s_iterator;s_iterator!=_rhs.endP;++s_iterator) { new (endP) T(*s_iterator); //placement new . ++endP; } } else { del(); T* TempfirstP=(T*) malloc ( sizeof (T)*_rhs.capcity()); T* TempendP=TempfirstP; T* TempCapcityP=TempfirstP+(_rhs.capcity()); cout<< "copy malloc:" <<TempfirstP<<endl; T* s_iterator=_rhs.firstP; for (s_iterator;s_iterator!=_rhs.endP;++s_iterator) { new (TempendP) T(*s_iterator); //placement new . ++TempendP; } firstP=TempfirstP; endP=TempendP; CapicityP=TempCapcityP; } return * this ; } template < typename T> MyVector2<T>::MyVector2(unsigned int _tsize):firstP((T*) malloc ( sizeof (T)*_tsize)) { endP=firstP; CapicityP=firstP+_tsize; } template < typename T> void MyVector2<T>::erace(unsigned int _index) { //endp 减1。index以下数据望上移动。 //:int类型的数据与unsigned int类型的数据进行比较时会把int类型的数据转换为unsigned int 类型的数据,然后再进行比较。 //坑太多。。。。这里size 为0的花。size-1为-1。按照规则会比无符号的0大。。。 if (_index>=0 && _index<= this ->size()-1 && this ->size()>0) // { T* titerator= this ->firstP+_index+1; for (titerator;titerator!= this ->endP;++titerator) { new ( this ->firstP+_index) T(*( this ->firstP+_index+1)); } --endP; } } template < typename T> unsigned int MyVector2<T>::size() const { return endP-firstP; } template < typename T> unsigned int MyVector2<T>::capcity() const { return CapicityP-firstP; } template < typename T> void MyVector2<T>::addEnd() { ++endP; } template < typename T> int MyVector2<T>::PushBack( const T& _T) { int result=-1; if (endP>=firstP && endP<CapicityP) { new (endP) T(_T); ++endP; } else { //MyVector2<T> temp=MyVector2(2*size());//最开始一直出错.debug才发现,犯了一个基础知识错误. //这里建立的对象,离开作用域会调用西够函数.所以直接分配内存,而不是建立临时对象.免去西构问题. T* TempfirstP=(T*) malloc ( sizeof (T)*2*size()); T* TempendP=TempfirstP; T* TempCapcityP=TempfirstP+(2*size()); cout<< "pushback malloc:" <<TempfirstP<<endl; T* s_iterator= this ->firstP; for (s_iterator;s_iterator!=( this ->endP);++s_iterator) { new (TempendP) T(*s_iterator); //placement new . ++TempendP; } del(); new (TempendP) T(_T); ++TempendP; firstP=TempfirstP; endP=TempendP; CapicityP=TempCapcityP; } return result; } template < typename T> T& MyVector2<T>::operator[](unsigned int _index) { if (_index>0) { return *(firstP+_index); } else { return *firstP; } } template < typename T> void MyVector2<T>::del() { cout<< "del:" <<firstP<<endl; free (firstP); } #endif // MYVECTOR2_H_INCLUDED |
main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | #include <iostream> #include <vector> #include "myvector2.h" using namespace std; //为什么mb[0]=b2;是ok的.但是设计myvector中firstP=_T;确不行? //为什么CapicityP=firstP+stepsize;防在函数体内每问题.而防入初始化却有问题? struct book { public : book():name( "" ),bn(0),price(0){} book( const string& _name, const int _bn, const double _price):name(_name),bn(_bn),price(_price){} book& operator=( const book& _lhs) { name=_lhs.name; bn=_lhs.bn; price=_lhs.price; return * this ; } book( const book& _rhs) { name=_rhs.name; bn=_rhs.bn; price=_rhs.price; } string bName() { return name; } void changeName( const string& _name) { name=_name; } ~book(){} private : string name; int bn; double price; }; void mainMyVector2(); void showInfo( const MyVector2<book>& books); int main() { mainMyVector2(); //mainString(); //mainMyVector(); return 0; } void mainMyVector2() { //实现功能基本:插入元素,pushback. //引用构造, //copy功能. //按索引返回. //删除索引位置元素. book b1=book( "c++" ,01,2.5); book b2=book( "c" ,02,2); book b3=book( "c#" ,03,3.1); cout<< "*************push back***********" <<endl; MyVector2<book> books1; //不需要book类有默认构造函数,因为使用的是c的malloc分配空间函数。而不是new建立数组。 books1.PushBack(b1); books1.PushBack(b2); books1.PushBack(b3); showInfo(books1); for ( int i=0;i!=40;++i) { books1.PushBack(b2); } showInfo(books1); cout<< "*************ref construct***********" <<endl; MyVector2<book> books2=books1; //注意这里是构造初始化而不是copy。 showInfo(books2); cout<< "**************copy***********" <<endl; MyVector2<book> books_capcity32; showInfo(books_capcity32); books_capcity32=books1; showInfo(books_capcity32); cout<< "*************index***********" <<endl; cout<< "index 38:" <<books_capcity32[38].bName()<< ". first:" <<books_capcity32[0].bName()<<endl; cout<< "*************earse***********" <<endl; MyVector2<book> books3; for ( int i=0;i!=books3.size();++i) { cout<<books3[i].bName()<<endl; } showInfo(books3); books3.erace(0); books3.PushBack(b1); books3.erace(0); for ( int i=0;i!=books3.size();++i) { cout<<books3[i].bName()<<endl; } showInfo(books3); books3.PushBack(b1); books3.PushBack(b2); books3.PushBack(b3); for ( int i=0;i!=books3.size();++i) { cout<<books3[i].bName()<<endl; } books3.erace(1); for ( int i=0;i!=books3.size();++i) { cout<<books3[i].bName()<<endl; } showInfo(books3); } void showInfo( const MyVector2<book>& books) { cout<< "size:" <<books.size()<< ". capcity:" <<books.capcity()<<endl; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步