从向量中删除vector::end

47

当我使用以下代码时,它能正常工作(什么也不做)吗?

 vector<T> v;
 v.erase(v.end());

我想使用类似于以下的内容:

 v.erase(std::find(...));

我应该检查v.end()是否为空吗?
C++.comCPPreference上都没有相关信息。

3个回答

40

标准没有详细说明,但在[sequence.reqmts]中定义了v.erase(q),“删除由q指向的元素”这意味着q必须实际上指向一个元素,而末尾迭代器则不是。将末尾迭代器传入是未定义行为。

不幸的是,你需要编写:

auto it = std::find(...);
if (it != <the part of ... that specifies the end of the range searched>) {
    v.erase(it);
}
当然,你可以定义:
template typename<Sequence, Iterator>
Iterator my_erase(Sequence &s, Iterator it) {
    if (it == s.end()) return it;
    return s.erase(it);
}

my_erase(v, std::find(v.begin(), v.end(), whatever));

c.erase() 在关联容器中返回 void,所以要将这个模板推广到所有容器,你需要一些 -> decltype 操作。


docs 上说:“在除了向量末尾之外的位置擦除元素会导致容器重新定位...”。看起来允许使用end()作为参数。而且没有明确说明相反的情况。我不喜欢这个... - Pavel
1
@Pavel:那么你将不得不与“cplusplus.com”的作者联系。它不是C++文档,标准才是C++文档。但它将position定义为“指向单个元素的迭代器”。结束迭代器并不指向单个元素。 - Steve Jessop
1
@Pavel他们说错了,应该写成end() - 1而不是“vector end”。 - emlai

29

删除end()函数(或查看end()函数的目标)都是未定义的行为。未定义的行为允许具有任何行为,包括在您的平台上“有效运行”。这并不意味着您应该这样做;这仍然是未定义的行为,在以后的某个时候我会以最糟糕的方式咬你。

根据您的目的,您可能希望考虑使用setunordered_set而不是vector


谢谢,我知道什么是UB,我只是想知道它是否真的是UB。 - RiaD
@Billy,我有一个问题。纯属好奇,end()-1 能用吗?这和 pop_back() 有什么不同? - Gaffi
3
只有容器非空时,"@Gaffi: end-1" 才能起作用,这与 "pop_back" 相同。 - Billy ONeal
@KerrekSB,是的,我知道我可以检查,这很容易:D。只是有点丑陋,我在考虑替换它:) - RiaD
@Billy,对我来说,set和even multiset都不行。删除操作很少发生。 - RiaD
显示剩余2条评论

7

你尝试过这个吗?

v.erase(remove_if(v.begin(), v.end(), (<your criteria>)), v.end());

1
缺乏其他正确答案并不会使你的答案变得正确。 - Billy ONeal
4
我不知道为什么这个帖子被点了踩(除非是因为起初的回答已经被编辑过)。目前的代码是正确的。 - David Rodríguez - dribeas
3
@DavidRodríguez-dribeas:最初发布时并不正确,现在已经经过编辑改正,我已取消了我的负评。 - Billy ONeal
1
它将删除所有符合<criteria>的元素,而不仅仅是第一个。 - RiaD
对我来说,我们为什么相信这个是安全的并不清楚,而 vec.erase(vec.end()) 明显不是。 - bobobobo
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接