标准库容器允许我们使用迭代器erase
和first
表示的last
范围。
std::vector<foo> bar;
// first it last it
bar.erase(bar.begin(), bar.end());
标准规定first
迭代器必须有效且可解除引用,而last
只需要有效。但是,如果first == last
,则first
不需要取消引用,因为erase
是无操作。这意味着以下是合法的:
bar.erase(bar.end(), bar.end());
但是,如果我只希望删除一个元素而不是一个范围,则迭代器必须是有效的和可解除引用,从而产生以下未定义的行为:
bar.erase(bar.end());
为什么这不是一个无操作?这是标准委员会的监督,将在未来的语言版本中加以解决,还是一个我没有注意到的深思熟虑的设计决策?
据我所知,它不会带来任何好处,但在执行以下操作时会产生额外的麻烦:
bar.erase(std::find(bar.begin(), bar.end(), thing));
答案 0 :(得分:3)
C ++习惯于在标准库中留下任何额外的工作,也称为#34;你不会为你不使用的东西付出代价。在这种情况下,单个迭代器版本需要将迭代器与结束迭代器进行比较。对于大多数情况,这种检查是多余的,这是额外的工作,虽然只是一小部分工作,但并没有被使用。
erase(iterator it):
if it != end: // we can't avoid this check now
// erase element
在过载占用范围的情况下,它在结束前自然停止。一个天真的实现可能如下:
erase(iterator first, iterator last):
while first != last:
erase(first++);
需要某种方式知道何时停止删除。在某些情况下,它可能更智能,例如memmove
一块内存来覆盖已擦除的内存,而不会分支,但这只会在特定情况下发生。
另请注意,通过此方式构建已检查版本比以其他方式更容易:
checked_erase(Container cont, iterator it):
if it != cont.end():
cont.erase(it);
答案 1 :(得分:1)
为什么这不是一个无操作?
为什么它会成为无操作?您正在调用专门设计用于删除单个元素的方法,并以不能删除任何元素的方式调用它。这没有任何意义。您可能会争辩说它应该抛出异常而不是具有未定义的行为,但我没有在您的问题中看到任何有效的参数使其明确定义为什么都不做,所以我认为没有理由认为它可能是监督。
您的示例并不令我信服:只要该项目在向量中是唯一的,就可以使用std::remove
而不是std::find
以简单的形式轻松表达。如果该项目不是唯一的,那么请更明确地指出要删除的项目数。
另一种方式:对于所有迭代器,erase(it)
相当于erase(it, it+1)
。包括结束迭代器。如果erase(it)
为未定义erase(it, it+1)
的结束迭代器定义OpaqueToken
,则会产生一个特殊例外,这会引入不一致。