第二次修改:
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
#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
#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;
}
