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的异常。

后者迭代器越界比较好理解,但是为空较难理解

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