從迭代器中取值切記需要判斷是否為空
例如:
1 vector<int> vtTest; 2 vtTest.clear(); 3 if (vtTest.empty()){ 4 return 0; 5 } 6 7 int *pTest = &vtTest[0];
如果沒有忘了判斷則會出現這樣的異常_DEBUG_ERROR("vector subscript out of range");
其實這條異常是Visual C++專有,在g++當中並不會出現,所取得的數值是0。可問題是你怎么區分里面所存的數據本身是0還是vector為空呢?
帶有容器的結構體不要使用memset清0
例如以下代碼:
1 struct _Test{ 2 int i; 3 vector<int> vtTest; 4 }; 5 6 _Test test; 7 memset(&test,0,sizeof(test)); 8 test.vtTest.push_back(0); 9 test.vtTest.push_back(0); 10 test.vtTest.push_back(0);
其實這部分代碼完全可以正常運行,但是如果加上以下代碼就一樣了
1 vector<int>::iterator it = test.vtTest.begin(); 2 it++;
問題就出在it++這條語句之上,此時會拋出vector iterator not incrementable
因為在自加的操作中,有這么一條判斷
1 if (this->_Getcont() == 0 2 || this->_Ptr == 0 3 || ((_Myvec *)this->_Getcont())->_Mylast <= this->_Ptr) 4 { // report error 5 _DEBUG_ERROR("vector iterator not incrementable"); 6 _SCL_SECURE_OUT_OF_RANGE; 7 }
在this->_Getcont()函數內部,其實現是這樣的;
return (_Myproxy == 0 ? 0 : _Myproxy->_Mycont);
一旦調用上面的memset(&test,0,sizeof(test));之后,vector的_Myproxy數據結構也被清0了,此時_Getcont()函數的返回值就是0,那么程序就會執行到_DEBUG_ERROR("vector iterator not incrementable");經過分析發現,_Myproxy變量是vector用來尋找相鄰的數值,而我們的清0操作導致這個鏈條斷裂了,破壞了vector的數據結構從而導致異常。但是g++編譯器並沒有以上問題,因為VS改寫了STL代碼。
其實memset清0操作對於結構體或者類都必須慎重,因為很容易破壞自身的數據結構,最典型的就是帶有虛函數的類,一旦清0連虛表都給破壞掉了。
vector內存控制
vector每次調用push_back的時候,如果之前內存夠用就直接插入,如果不夠用了就重新申請一塊更大的內存(g++是在原基礎上增加一倍長度,VS是增加百分之五十),然后將數據拷貝到新內存當中,釋放原內存,再插入新數據。
那么有兩個問題,第一,如果能預測到數據量是固定數字,一定要首先預備一塊內存,然后插入數據,這樣第一避免多次重復申請釋放,拷貝等耗資源和時間的無用操作,也可以避免多出一塊並不會使用的內存。
其次如果從vector中刪除元素,由於vector內存只增不減,當你申請一萬個元素空間,刪除了9999個,但是其占用仍然是10000個元素空間,如果條件允許,其實可以考慮增加策略來避免內存浪費,因為這些內存只有在析構的時候才會徹底釋放掉。如果是指針則必須要手動析構,先遍歷逐一delete,然后clear。
由於vector是申請的一塊內存,所以如果要從首部刪除元素會導致后面的所有元素向前移動一個單位,如果一直這么操作其占用可想而知。。。