【问题标题】:iterator - no matching erase function in c++11迭代器 - 在 C++11 中没有匹配的擦除函数
【发布时间】:2013-12-16 20:42:54
【问题描述】:

我无法解释这种行为:

for (vector<File>::const_iterator it = this->files.begin(); it != this->files.end(); ++it) {
    if (...) erase(it); // break after, no need of ++it in else branch
}

其中 File 是我自己的类(不包括标准),而 this->files 是 Files 的向量

当我编译得到的代码时(见 第 2 行

Path.cpp: In member function ‘void Path::rmFile(File&)’:
Path.cpp:190:24: error: no matching function for call to ‘std::vector<File>::erase(std::vector<File>::const_iterator&)’
Path.cpp:190:24: note: candidates are:
In file included from /usr/include/c++/4.7/vector:70:0,
             from Path.h:5,
             from Path.cpp:1:
/usr/include/c++/4.7/bits/vector.tcc:135:5: note: std::vector<_Tp, _Alloc>::iterator     std::vector<_Tp, _Alloc>::erase(std::vector<_Tp, _Alloc>::iterator) [with _Tp = File; _Alloc =     std::allocator<File>; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<File*,     std::vector<File> >; typename std::_Vector_base<_Tp, _Alloc>::pointer = File*]
/usr/include/c++/4.7/bits/vector.tcc:135:5: note:   no known conversion for argument 1     from ‘std::vector<File>::const_iterator {aka __gnu_cxx::__normal_iterator<const File*,     std::vector<File> >}’ to ‘std::vector<File>::iterator {aka __gnu_cxx::__normal_iterator<File*,     std::vector<File> >}’
/usr/include/c++/4.7/bits/vector.tcc:147:5: note: std::vector<_Tp, _Alloc>::iterator     std::vector<_Tp, _Alloc>::erase(std::vector<_Tp, _Alloc>::iterator, std::vector<_Tp,     _Alloc>::iterator) [with _Tp = File; _Alloc = std::allocator<File>; std::vector<_Tp,     _Alloc>::iterator = __gnu_cxx::__normal_iterator<File*, std::vector<File> >; typename     std::_Vector_base<_Tp, _Alloc>::pointer = File*]
/usr/include/c++/4.7/bits/vector.tcc:147:5: note:   candidate expects 2 arguments, 1 provided
make: *** [Path.o] Error 1

即使doc 说没问题,但是错误no matching function for call to std::vector::erase(std::vector::const_iterator&) 真的很奇怪。

我真的需要能够通过迭代器删除向量项。有人可以帮我吗? 提前谢谢。

【问题讨论】:

  • const_iterator 表示没有修改。
  • @chris const_iterator 表示没有修改通过这个迭代器。如果你想调用erase,你已经需要一种非常量的方式来访问容器。迭代器仅仅提供了修改的位置,因此在 C++11 中已经解除了限制。
  • 我猜这个问题是重复的:stackoverflow.com/q/15987893/420683 你需要更新版本的 libstdc++; AFAIK 现在已修复(SVN),但我不知道从哪个版本开始。
  • @DyP,啊,好点子。
  • 不完全确定您的评论是什么意思。在erase(it)之后,绝对不能做++it

标签: c++ c++11 vector iterator const-iterator


【解决方案1】:

这里有三个错误。

for (vector<File>::const_iterator it = this->files.begin(); it != this->files.end(); ++it) {
    if (...) erase(it); // break after, no need of ++it in else branch
}

第一个错误是您错误地将代码剪切并粘贴到 StackOverflow 中。你要粘贴的是

for (vector<File>::const_iterator it = this->files.begin(); it != this->files.end(); ++it) {
    if (...) this->files.erase(it); // break after, no need of ++it in else branch
}

第二个错误是编译器警告您的:无法通过const_iterator 修改集合。 (编辑:Okay, apparently C++11 added such a way, but libstdc++ didn't support it immediately.)这就是const_ 部分的意思!如果要修改集合,请使用普通的旧 iterator

for (vector<File>::iterator it = this->files.begin(); it != this->files.end(); ++it) {
    if (...) this->files.erase(it); // LOOK OUT, THERE'S STILL A BUG
}

第三个错误是,一旦您对集合调用 std::vector::erase,该集合中的所有迭代器(和 const_iterators)都将变得不可用。对此的标准术语是erase 使迭代器无效。 (这样做的原因是std::vector 的行为基本上就像一个大的堆分配缓冲区,并且在向量上调用resize 可以在缓冲区,并且调用 erase 被允许调用 resize (因为如果你 erase 向量中的一半元素,你可能期望堆分配相应地缩小)。

所以,使用这种幼稚的 for 循环方法,您尝试执行的操作将行不通。您需要做的是使用标准算法namely remove_if:

#include <algorithm>

auto predicate = [](const File& f) { return f.ShouldBeErasedOrWhatever(); }
auto newEndIterator = std::remove_if(this->files.begin(), this->files.end(), predicate);
this->files.erase(newEndIterator, this->files.end());  // erase everything after "newEndIterator"

f.ShouldBeErasedOrWhatever() 替换为原始代码中的“...”。现在你有了有效的、惯用的 C++11,它做正确的事——没有错误!


(1) – 注意“相当于realloc”:当然不是真的 realloc;它实际上是一个类型安全的过程,可以根据需要调用移动构造函数和析构函数。 vector 知道在 C++ 中使用 memcpy 任意对象通常是不安全的。

【讨论】:

    【解决方案2】:

    假设您的示例代码不正确并且它确实是files.erase(it),那么const_iterator 版本仅在C++11 中添加,因为您没有使用auto,所以看起来您没有。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-22
      • 1970-01-01
      • 2017-05-01
      相关资源
      最近更新 更多