我想处理vector<int>
容器中的每个节点。
假设vector<int>
包含0,1,2和3,迭代器指向2。
我想擦除2而不会丢失迭代器位置的信息,因为我想在擦除2后处理“3”。
这是我所做的,但输出并没有显示我的意图。
以下是我的问题:
Q1)执行vector<int>::iterator oldIter = iter;
时
oldIter
是否创建了一个新的迭代器对象?
Q2)为什么迭代器的值在递增后保持不变?
Q3)擦除节点而不丢失的好方法是什么 迭代器的位置?
问题4)最后,一个微不足道的问题。我试过cout << iter;
,但它不起作用。那是为什么?
以下是代码:
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> vContainer;
vector<int>::iterator iter;
vContainer.push_back(0);
vContainer.push_back(1);
vContainer.push_back(2);
vContainer.push_back(3);
for(int i = 0; i < vContainer.size(); i++){
cout << vContainer[i] << endl;
}
printf("iter: %x\n", iter);
iter = vContainer.begin();
// Move the itertor to the 2.
while(*iter != 2){
iter++;
}
printf("iter: %x\n", iter);
vector<int>::iterator oldIter = iter;
printf("\nBefore erase(oldIter)\n");
printf("oldIter: %x\n", oldIter);
printf("iter: %x\n", iter);
iter++;
printf("\nAfter incrementing iter\n");
printf("oldIter: %x\n", oldIter);
printf("iter: %x\n", iter);
vContainer.erase(oldIter);
printf("\nAfter erase(oldIter)\n");
printf("oldIter: %x\n", oldIter);
printf("iter: %x\n", iter);
for(int i = 0; i < vContainer.size(); i++){
cout << vContainer[i] << endl;
}
}
答案 0 :(得分:2)
执行
vector<int>::iterator oldIter = iter;
时,是否为oldIter 创建一个新的迭代器对象?
是
为什么递增后迭代器的值保持不变 它?
它没有。是什么让你得出结论呢?你的printf
陈述?那些都是无效的。 printf
不知道如何处理向量迭代器。您对它的调用是未定义的行为。
在不丢失节点位置的情况下擦除节点有什么好方法 迭代器?
捕获erase
来电的返回值。
iter = vContainer.erase(iter);
最后,一个微不足道的问题。我试过cout&lt;&lt; ITER;但事实并非如此 工作。那是为什么?
因为没有operator<<
重载,左边是std::ostream
,右边是矢量迭代器。与printf
不同,std::ostream::operator<<
是类型安全的,因此您将获得编译时错误,而不是运行时未定义的行为。
答案 1 :(得分:2)
理想情况下,不单独删除节点。相反,将std::remove_if()
与std::vector<...>::erase()
结合使用:这会将潜在的二次算法转换为线性算法。也就是说,你会使用这样的东西
vContainer.erase(std::remove_if(vContainer.begin(),
vContainer.end(),
[](int value){ return someCondition(value); }),
vContainer.end());
否则,最简单的方法可能只是使用偏移量恢复位置:
int offset(std::distance(vContainer.begin(), it));
vContainer.erase(it);
it = vContainer.begin() + offset;
由于erase(it)
将移动位置it
之后的所有对象,但它相当昂贵。使用像std::remove_if()
这样的算法来聚合更改并将每个元素最多移动一次,而不是每erase()
移动一次,效率要高得多。
解决您的具体问题:
std::vector<int>::iterator oldIter = iter
显然会创建iter
的副本。但请注意,使用it
时,引用erase(it)
引用的对象或跟随该对象的所有迭代器都将失效。std::distance(v.begin(), it)
(假设it
是v.begin()
范围内的迭代器} v.end()
)。printf()
打印的内容并不意味着什么,因为类型%x
只能用于整数值,并且在特定位置使用不同类型的是未定义的行为。请参阅上文,了解如何合理地指示迭代器位置。请注意std::distance(v.begin(), it)
的结果是一些整数类型:最好用IOStreams打印它,它会自动计算出类型,而不是为printf()
的格式说明符猜测它的类型。