C++erase()

偶然發現了當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的異常。

後者迭代器越界比較好理解,但是爲空較難理解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章