函數模板提供了一種機制經過它咱們能夠保留函數定義和函數調用的語義在一個程序位置上封裝了一段代碼確保在函數調用以前實參只被計算一次.ios
函數模板提供一個種用來自動生成各類類型函數實例的算法程序員對於函數接口參數和返回類型中的所有或者部分類型進行參數化(parameterize)而函數體保持不變.程序員
函數模板使用注意事項:
算法
一、每一個函數模板前邊都須要添加模板聲明例如:template<typename T>ide
二、在模板類的使用時,注意其類型改變,例如:函數
template<typename T> class SeqList {}; 該模板類的類型爲SeqList<T> ,SeqList僅爲一個類名
三、函數模板不能在.h文件和.cpp文件中分開編譯測試
在實現順序表的時候咱們須要其能夠存儲任何類型的數據。可是對於string類型對象要特別考慮。下面咱們來分析一下經常使用的拷貝的方法。
this
1)逐個對象的複製spa
優勢:對於數據的類型無需特別考慮指針
缺點:拷貝的效率比較低orm
2)memcpy()複製
優勢:拷貝的效率比較高
缺點:在涉及指針的複製時,可能出現多個指針指向同一份空間,致使內存釋放屢次引發程序崩潰。
string類深度剖析
在不一樣的編譯器中string類的空間大小不一樣,可是能夠肯定的是,string類存在一個16個字節大小的buffer空間用於存放長度較短的字符來提升效率,還有一個4字節的——ptr用於指向當字符長度大於15時的字符串空間,還有兩個4字節的_size和_capacity用來表示大小和容量。總共28個字節。
這裏就須要考慮在擴容和拷貝構造時的複製了,若是字符串的長度大於15個,則使用memcpy()僅僅是數值的拷貝,並不會爲_ptr申請空間會致使多個指針同時指向同一份空間,使得該空間在釋放時釋放屢次致使程序崩潰。
解決方法一:
通通採用單個賦值的,可是效率比較低。
解決方法二(最優解):
類型萃取,將內置類型和非內置類型分開copy的效率比較高。
void Copy(T* dest, const T* src, size_t size) { if (TypeTraits<T>::IsPoodType().Get())//類型萃取,內置類型 { memcpy(dest, src, sizeof(T)*size); } else//非內置類型 { for (size_t i = 0; i < size; i++) { dest[i] = src[i]; } } } struct TrueType { bool Get() { return true; } }; struct FalseType { bool Get() { return false; } }; template<typename T> struct TypeTraits { typedef FalseType IsPoodType;//內嵌型別 }; //特化 template<> struct TypeTraits<int> { typedef TrueType IsPoodType; }; template<> struct TypeTraits<unsigned int> { typedef TrueType IsPoodType; }; template<> struct TypeTraits<char> { typedef TrueType IsPoodType; }; template<> struct TypeTraits<unsigned char> { typedef TrueType IsPoodType; }; template<> struct TypeTraits<double> { typedef TrueType IsPoodType; }; template<> struct TypeTraits<bool> { typedef TrueType IsPoodType; }; template<> struct TypeTraits<float> { typedef TrueType IsPoodType; }; template<> struct TypeTraits<short> { typedef TrueType IsPoodType; }; template<> struct TypeTraits<unsigned short> { typedef TrueType IsPoodType; }; template<> struct TypeTraits<long long> { typedef TrueType IsPoodType; }; template<> struct TypeTraits<long double> { typedef TrueType IsPoodType; };
#include <iostream> #include<string> using namespace std; const int SIZE = 3;//構造對象的默認大小 const int DEAFAULT = 3;//每次擴容的大小 template<typename T> class SeqList { public: //構造函數 SeqList(); //拷貝構造函數 SeqList(const SeqList& l); //賦值 SeqList<T> operator=(SeqList l); //析構函數 ~SeqList(); public: void PushBack(const T& d); void PopBack(); void PushFront(const T& d); void PopFront(); void SortList(); void Reverse(); T* Find(const T& d); void Insert(int pos, const T& x); void Remove(T x); void RemoveAll(T x); void CheckCapacity(); void Print(); private: T* _data; int _size; int _capacity; }; template<typename T> void SeqList<T>::Print() { int i = 0; for (i = 0; i < _size; i++) { cout << _data[i] << " "; } cout << endl; } template<typename T> //構造函數 SeqList<T>::SeqList() :_data(new T[SIZE]) , _size(0) , _capacity(SIZE) {} template<typename T> //拷貝構造函數 SeqList<T>::SeqList(const SeqList& l) { _data = new T[l._size]; //int i = 0; //for (i = 0; i < l._size; i++)//逐個拷貝 //{ // _data[i] = l._data[i]; //} Copy(_data, l._data, l._size); _size = l._size; _capacity = _size; } template<typename T> //賦值 SeqList<T> SeqList<T>:: operator=(SeqList l) { swap(_data, l._data); _size = l._size; _capacity = l._capacity; return *this; } template<typename T> //析構函數 SeqList<T>::~SeqList() { if (_data != NULL) { delete[] _data; _data = NULL; } } template<typename T> void SeqList<T>::CheckCapacity()//檢測容量 { if (_size == _capacity)//擴容 { T* tmp = new T[_capacity + DEAFAULT]; //memcpy(tmp, _data, sizeof(T)*_size);淺拷貝,致使程序崩潰 //int i = 0; //for (i = 0; i < _size; i++)//逐個拷貝 //{ // tmp[i] = _data[i]; //} Copy(tmp, _data, _size); delete[] _data; _data = tmp; _capacity += DEAFAULT; } } template<typename T> void SeqList<T>::PushBack(const T& d) { CheckCapacity(); _data[_size] = d; _size++; } template<typename T> void SeqList<T>::PopBack() { if (_size == 0) { return; } _size--; } template<typename T> void SeqList<T>::PushFront(const T& d) { CheckCapacity(); int i = 0; for (i = _size-1; i >= 0; i--) { _data[i + 1] = _data[i]; } _data[0] = d; _size++; } template<typename T> void SeqList<T>::PopFront() { if (_size == 0) { return; } int i = 0; for (i = 1; i < _size; i++) { _data[i - 1] = _data[i]; } _size--; } template<typename T> void SeqList<T>::SortList() { int i = _size; bool flag = true;//標誌位,當順序表已是有序的時候則不須要再排序提升效率 for (i = 1; i < _size && flag; i++) { int j = 0; flag = false; for (j = 0; j < _size - i; j++) { if (_data[j] > _data[j + 1]) { flag = true; swap(_data[j], _data[j + 1]); } } } } template<typename T> void SeqList<T>::Reverse() { int left = 0; int right = _size; while (left < right) { swap(_data[left++], _data[right--]); } } template<typename T> T* SeqList<T>::Find(const T& d) { int i = 0; for (i = 0; i < _size; i++) { if (_data[i] == d) { return &_data[i];//找到返回地址 } } return NULL;//沒有找到 } template<typename T> void SeqList<T>::Insert(int pos, const T& x) { if (pos > 0 && pos <= _size)//判斷位置的正確性 { CheckCapacity(); int i = 0; for (i = _size - 1; i >pos-2; i--) { _data[i + 1] = _data[i]; } _data[pos - 1] = x; _size++; } } template<typename T> void SeqList<T>::Remove(T x) { int i = 0; for (i = 0; i < _size; i++) { if (x == _data[i]) { for (int j = i; j < _size-1; j++) { _data[j] = _data[j + 1]; } _size--; return; } } } template<typename T> void SeqList<T>::RemoveAll(T x) { int i = 0; for (i = 0; i < _size; i++) { if (x == _data[i]) { Remove(x); i--;//保留下標,刪除以後從當前繼續尋找,以避免順序表遍歷漏掉。 } } } void test1() { SeqList<string> l; //l.PushBack(1); //l.PushBack(2); //l.PushBack(3); //l.PushBack(4); //l.Print(); //l.PopBack(); //l.Print(); //l.PopBack(); //l.Print(); //l.PopBack(); //l.Print(); l.PushFront("11111"); l.PushFront("22222"); //l.PushFront("333333333333333333333333333333333333"); l.PushFront("33333"); l.PushFront("44444"); //l.PushFront("11111"); l.Print(); cout << sizeof(string) << endl; //cout << l.Find("11111") << endl; ////cout << l.Find(0) << endl; //l.Insert(4, "00000"); //l.Print(); //l.RemoveAll("11111"); //l.Print(); //l.SortList(); ////l.PopBack(); //l.Print(); //l.PopBack(); //l.Print(); //l.PopBack(); //l.Print(); } int main() { test1(); getchar(); return 0; }
當使用memcpy()時
測試代碼
l.PushFront("11111"); l.PushFront("22222"); //l.PushFront("333333333333333333333333333333333333"); l.PushFront("33333"); l.PushFront("44444");
結果能夠正常運行
可是在字符串長度比較長時
l.PushFront("11111"); l.PushFront("22222"); l.PushFront("333333333333333333333333333333333333"); //l.PushFront("33333"); l.PushFront("44444");
程序崩潰