偶然发现了当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的异常。
后者迭代器越界比较好理解,但是为空较难理解