偶然發現了當vecotr在erase最後一個iter之後,仍然可以++代表一個值,而不爲空。
vector<int> nums={3,2,3,4};
int val=3;
auto iter=nums.begin();
while(*iter){
if(*iter==val)
nums.erase(iter);
else
iter++;
}
將while的條件修改爲iter!=nums.end()即可。
erase(iter)
當erase的參數是一個迭代器的時候,函數返回的是欲刪除元素之後的元素的迭代器;當參數是指向最後一個元素的迭代器時,返回的是.end()
vector<int> nums={3,2,3,4};
auto iter=nums.begin()+1;
nums.erase(iter);
cout<<*iter<<endl;
cout<<*(nums.begin()+1)<<endl;
cout<<*(nums.begin()+2)<<endl;
cout<<*(nums.begin()+3)<<endl;
if((nums.begin()+3)==nums.end())
cout<<"1"<<endl;
cout<<nums.size()<<endl;
//再次刪除
cout<<"再次刪除"<<endl;
nums.erase(iter);
cout<<*iter<<endl;
cout<<*(nums.begin()+1)<<endl;
cout<<*(nums.begin()+2)<<endl;
cout<<*(nums.begin()+3)<<endl;
可以看到刪除2之後,iter爲3是nums.begin()+1,第三個元素nums.begin()+2是4,但是第四個元素nums.begin()+3還是4。
再刪除iter之後,iter爲4是nums.begin()+1,第三個元素nums.begin()+2是4,但是第四個元素nums.begin()+3還是4。
猜測erase只是將後面的元素向前移動了一個,但是沒有刪除後面的,遂查看源碼。
iterator erase(iterator position){
if(position +1 != end())
copy(position +1, finish, postion);
--finish;
destroy(finish);
return position;
}
這裏finish就是end()
finish的定義
每次調用end()的時候返回的就是finish,
可以看到果真是這樣,進行復制,但是源碼中對於finish的元素是進行銷燬的。
1.懷疑是因爲Ubuntu中的C++與VS的區別,改天用VS跑一下。
2.對於刪除元素後面的迭代器可以理解爲,刪除某元素之後,所有元素錯位,最後一個元素刪除。
查看destroy的源碼。
destory同erase一樣分爲兩個版本
template <class T>
inline void destroy(T* pointer) {
pointer->~T(); // 直接調用析構函數
}
template <class ForwardIterator>
inline void destroy(ForwardIterator first, ForwardIterator last) {
__destroy(first, last, value_type(first));
}
這裏只用到第一個版本的destroy(),直接調用T類型的析構函數。
在我們的例子中T爲int,int 爲內置類型,沒有析構函數,所以erase之後,沒有進行內存的刪除,只是將finish進行了前移。
寫了一個類,再自定義析構函數,來驗證一下
class A{
public:
A(int a):a(a){};
~A(){a=0};
int a;
};
int main() {
// vector<int> nums={3,2,3,4};
vector<A> nums={A(1),A(2),A(3),A(4)};
auto iter=nums.begin()+1;
nums.erase(iter);
cout<<(*iter).a<<endl;
cout<<(nums.begin()+1)->a<<endl;
cout<<(nums.begin()+2)->a<<endl;
cout<<(nums.begin()+3)->a<<endl;
if((nums.begin()+3)==nums.end())
cout<<"1"<<endl;
cout<<nums.size()<<endl;
}
結果如下:
這樣就清晰了。反之,若我們自定義的析構函數中沒有寫a=0;那麼仍然是int類型析構,則仍然存在,不會釋放內存。
在英文版的primer中,"the destructor does nothing to destroy members of built-in or pointer type",也就是說無論何種類型的析構函數都不會對內置類型做任何處理,只要過了生存週期,系統會自動釋放。
在VS中調試,發現DEBUG模式會出現錯誤,在RELEASE模式下不報錯。。。
在DEBUG模式下
在*iter的時候會出現_Mycont爲空的異常,
*(nums.begin()+3)會出現_Ptr>_Mycont->_Mylast的異常。
後者迭代器越界比較好理解,但是爲空較難理解