简体   繁体   English

迭代器-C ++ 11中没有匹配的擦除功能

[英]iterator - no matching erase function in c++11

I can't exmplain this behaviour: 我无法举例说明这种行为:

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
}

where File is my own class (std not included) and this->files is vector of Files 其中File是我自己的类(不包括std),而this-> files是Files的向量

when I compile the code I get (see line 2 ) 当我编译代码时(请参阅第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

even the doc says it's ok, but error no matching function for call to std::vector::erase(std::vector::const_iterator&) is really wierd. 甚至文档都说可以,但是没有错误匹配函数来调用std :: vector :: erase(std :: vector :: const_iterator&)确实很奇怪。

I really need to be able to delete vector item by iterator. 我真的需要能够通过迭代器删除矢量项。 Can anybody help me please? 有人可以帮我吗? Thaks in advance. 提前解冻。

You have three bugs here. 这里有三个错误。

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
}

The first bug is that you incorrectly cut-and-pasted your code into StackOverflow. 第一个错误是您错误地将代码剪切并粘贴到StackOverflow中。 What you meant to paste was 你要粘贴的是

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
}

The second bug is what the compiler is warning you about: there's no way to modify a collection through a const_iterator . 第二个错误是编译器警告您的:无法通过const_iterator修改集合。 (EDIT: Okay, apparently C++11 added such a way, but libstdc++ didn't support it immediately. ) That's what the const_ part means! (编辑: 好吧,显然C ++ 11添加了这样一种方法,但是libstdc ++并不立即支持它。 )这就是const_部分的意思! If you want to modify the collection, use a plain old iterator : 如果要修改集合,请使用普通的旧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
}

The third bug is that once you call std::vector::erase on a collection, all iterators (and const_iterator s) into that collection become unusable . 第三个错误是,一旦您对集合调用std::vector::erase ,该集合中的所有迭代器(和const_iterator )都将变得不可用 The Standard terminology for this is that erase invalidates iterators . 对此的标准术语是: erase 使迭代器无效 (The reason for this is that std::vector behaves basically like a big heap-allocated buffer, and calling resize on the vector is allowed to do the equivalent of realloc (1) on the buffer, and calling erase is allowed to call resize (because if you erase half the elements in the vector, you're probably expecting the heap-allocation to shrink accordingly).) (这样做的原因是std::vector行为基本上就像一个大的堆分配缓冲区,并且允许在vector上调用resize等效于在缓冲区上执行realloc (1) ,并且允许调用erase来调用resize (因为如果erase向量中的一半元素,则可能期望堆分配相应地缩小)。

So, what you're trying to do won't work using that naive for-loop approach. 因此,使用这种幼稚的for循环方法将无法正常工作 What you need to do is use a standard algorithm , namely remove_if : 您需要做的是使用标准算法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"

Replace f.ShouldBeErasedOrWhatever() with whatever your " ... " is in the original code. f.ShouldBeErasedOrWhatever()替换为原始代码中的“ ... ”。 Now you have valid, idiomatic C++11 that does the right thing — with no bugs! 现在,您拥有有效的,惯用的C ++ 11,可以正确地完成工作-没有错误!


(1) – Note on "the equivalent of realloc ": Of course it's not really realloc ; (1) –关于“等价于realloc ”的注释:当然,它并不是真正的 realloc it's really a type-safe process that calls move-constructors and destructors as needed. 这实际上是一个类型安全的过程,可以根据需要调用move构造函数和析构函数。 vector knows it's not generally safe to memcpy arbitrary objects in C++. vector知道它不是一般安全memcpy在C ++中的任意对象。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM