frontpage做的網(wǎng)站好不好關(guān)鍵詞在線聽免費
??個人主頁:?熬夜學編程的小林
💗系列專欄:?【C語言詳解】?【數(shù)據(jù)結(jié)構(gòu)詳解】【C++詳解】
目錄
1、容量操作
2、內(nèi)容修改操作
3、打印函數(shù)
4、迭代器失效
4.1、什么是迭代器失效
4.2、哪些操作會引起迭代器失效
總結(jié)
1、容量操作
size()、capacity()
獲取容器的有效數(shù)據(jù)個數(shù)(連續(xù)內(nèi)存空間的指針相減計算的就是間隔的元素個數(shù))和分配給當前空間的大小,以元素個數(shù)表示。
size_t size() const
{return _finish - _start;
}
size_t capacity() const
{return _endofstorage - _start;
}
?reserve(size_t n)
擴容。如果n大于當前容量則擴容,小于等于當前容量則不處理。
void reserve(size_t n)//將容量個數(shù)擴大到n
{if (n > capacity())//大于容量才擴容{size_t old_size = size();T* tmp = new T[n];memcpy(tmp, _start, sizeof(T) * size());delete[] _start;//加[]_start = tmp;//_finish = _start + size();//_start的地址改變了 size()結(jié)果變化_finish = _start + old_size;_endofstorage = _start + n;}
}
這里我們開空間完成的是一個深拷貝的過程,用 memcpy 將舊數(shù)組中的數(shù)據(jù)拷貝到新數(shù)組,但是memcpy 在這里基于字節(jié)的拷貝,即淺拷貝,那么,如果我們vector實例化為string類,這里string類進行淺拷貝會涉及到二次釋放等問題。
解決辦法:
通過一個循環(huán),使用賦值操作符(自定義類型會調(diào)用賦值操作符重載)逐個拷貝舊數(shù)組中的元素到新數(shù)組。
void reserve(size_t n)//將容量個數(shù)擴大到n
{if (n > capacity())//大于容量才擴容{size_t old_size = size();T* tmp = new T[n];for (size_t i = 0; i < old_size; i++){tmp[i] = _start[i];//調(diào)用賦值操作符重載,深拷貝}delete[] _start;//加[]_start = tmp;//_finish = _start + size();//_start的地址改變了 size()結(jié)果變化_finish = _start + old_size;_endofstorage = _start + n;}
}
?注意:
需要提前計算原空間的大小,防止后面計算的大小是錯誤的,因為擴容的時候_start指針會修改指向,而_finish還指向原空間。
resize(size_t n)
調(diào)整容器的大小,使其包含n個元素。
如果n小于當前容器大小,則內(nèi)容將減少到其前n個元素,刪除超出的元素(并銷毀它們)。
如果n大于當前容器大小,則通過在末尾插入所需數(shù)量的元素來擴展內(nèi)容,以達到n的大小。如果指定了val,則將新元素初始化為val,否則初始化為缺省值。
如果n也大于當前容器容量,則自動重新分配所分配的存儲空間。
void resize(size_t n,const T& val=T())//將容量修改為n個,并初始化為val
{if (n > capacity()){//擴容reserve(n);while (_finish < _start + n){*_finish = val;++_finish;}}else{//刪除_finish = _start + n;//更改_finish位置即可,一般不縮容}
}
注意:
當 n 小于當前容量時,只需修改 _finish 指向即可,一般情況不縮容,如需縮容,可以調(diào)用shrink_to_fit()縮容函數(shù)。
2、內(nèi)容修改操作
push_back()
尾插數(shù)據(jù)。即在_finish位置插入數(shù)據(jù),在插入數(shù)據(jù)之前需要判斷空間是否已滿。
void push_back(const T& val)
{if (_finish == _endofstorage)//擴容{reserve(capacity() == 0 ? 4 : 2 * capacity());}*_finish = val;++_finish;
}
?pop_back()
尾刪數(shù)據(jù)(有數(shù)據(jù)才能刪)。刪除最后一個數(shù)據(jù),修改_finish指向即可。
void pop_back()
{assert(!empty());--_finish;
}
empty()
判斷容器是否為空(判斷_start與_finish指向是否一致),為空返回true,否則返回false。?
bool empty()
{return _start == _finish;
}
insert()?
在pos位置插入數(shù)據(jù)。
1.使用斷言保證在[_start,_finish]區(qū)間插入數(shù)據(jù)
2.判斷是否需要擴容,擴容則可能出現(xiàn)迭代器失效情況,則需要提前計算pos 位置與 _start之間的距離。
3.將[pos,_finish)之間的數(shù)據(jù)都向后挪動一步,再pos位置插入數(shù)據(jù)。
4.最后返回新的pos位置。
iterator insert(iterator pos, const T& val)//在pos位置插入val
{assert(pos >= _start);assert(pos <= _finish);//擴容if (_finish == _endofstorage){size_t len = pos - _start;//標記pos與原數(shù)組起點的長度reserve(capacity() == 0 ? 4 : 2 * capacity());pos = _start + len;//擴容_start的指向修改,pos也需修改}//移動數(shù)據(jù)iterator it = _finish - 1;while (it >= pos){*(it + 1) = *it;--it;}//填充數(shù)據(jù)*pos = val;++_finish;return pos;//返回新的pos位置
}
?erase()
刪除pos位置的數(shù)據(jù)。
1.使用斷言保證在[_start,_finish)區(qū)間刪除數(shù)據(jù),此處跟插入不同,不能刪除_finsih位置數(shù)據(jù)
2.將[pos + 1,_finish)之間的數(shù)據(jù)都向前挪動一步。
iterator erase(iterator pos)//刪除pos位置數(shù)
{assert(pos >= _start);assert(pos < _finish);//iterator it = pos;iterator it = pos + 1;while (it < _finish){//*it = *(it + 1);//it = pos; 越界*(it - 1) = *it;it++;}--_finish;return pos;
}
erase 返回值是一個迭代器,指向原來pos位置的下一個位置,即刪除操作之后的pos位置。
push_back()? pop_back()
尾插和尾刪函數(shù),使用insert()和erase()函數(shù)調(diào)用。
void push_back(const T& val)
{insert(end(), val);//在end()位置插入數(shù)據(jù)
}void pop_back()
{erase(end() - 1);//刪除end()前面位置數(shù)據(jù)
}
3、打印函數(shù)
print_vector()
打印vector容器的數(shù)據(jù)(任意類型)。
template<class T>//函數(shù)模板
void print_vector(const vector<T>& v)
{//前面加typename則沒有問題,表示iterator是一個類型//typename vector<T>::iterator it = v.begin();auto it = v.begin();//此處使用auto則可以避免此問題while (it != v.end()){cout << *it << " ";it++;//指向下一個位置}cout << endl;
}
?注意:
顯示訪問迭代器時,需要在前面加關(guān)鍵字typename保證iterator是一個類型,或者直接使用auto。
4、迭代器失效
4.1、什么是迭代器失效
迭代器的作用:主要作用就是讓算法能夠不用關(guān)心底層數(shù)據(jù)結(jié)構(gòu),其底層實際就是一個指針,或者是對指針進行了封裝。
迭代器失效,實際就是迭代器底層對應指針所指向的空間被銷毀了,而使用一塊已經(jīng)被釋放的空間,造成的后果是程序崩潰(即如果繼續(xù)使用已經(jīng)失效的迭代器,程序可能會崩潰)。我們可以從以下三步進行分析:
- [1]迭代器的本質(zhì)就是指針,迭代器失效就是指針失效。
- [2]指針失效:指針指向的空間是非法的。
- [3]指針指向非法空間:指向了被釋放的空間?或者?越界訪問?。
4.2、哪些操作會引起迭代器失效
- 所有可能會引起擴容的操作都可能會導致迭代器失效。如:resize、reserve、insert、assign、push_back等 ?-------------- ?野指針引起的迭代器失效
- 指定位置的插入和刪除都會都可能會導致迭代器失效。如: insert 、erase ----------------- ? 迭代器指向的位置意義發(fā)生改變
注意:
上述可能會引起迭代器失效的問題,代碼中基本已經(jīng)解決,如果uu們發(fā)現(xiàn)解決的有問題可以私信博主喔!!!
總結(jié)
本篇博客就結(jié)束啦,謝謝大家的觀看,如果公主少年們有好的建議可以留言喔,謝謝大家啦!