检查迭代器是否有效

有什么办法来检查一个迭代器(无论是从vector,列表,双向…)是(仍然)无法引用,即没有失效?

我一直在使用trycatch ,但有没有更直接的方法来做到这一点?

例子:(不起作用)

 list<int> l; for (i = 1; i<10; i++) { l.push_back(i * 10); } itd = l.begin(); itd++; if (something) { l.erase(itd); } /* now, in other place.. check if itd points to somewhere meaningful */ if (itd != l.end()) { // blablabla } 

我假设你的意思是“是一个有效的迭代器”,它由于容器的改变(例如插入/删除/从一个向量)而没有失效。 在这种情况下,不,你不能确定一个迭代器是否安全地无法引用。

正如jdehaan所说,如果迭代器没有失效,并指向一个容器,你可以通过比较container.end()来检查。

但是,请注意,如果迭代器是单数的 – 因为它没有被初始化,或者在对容器进行变异操作(例如,当增加向量的容量时,向量的迭代器失效),它变得无效 – 唯一的操作你被允许执行它是任务。 换句话说,你不能检查一个迭代器是否是单数的。

 std::vector<int>::iterator iter = vec.begin(); vec.resize(vec.capacity() + 1); // iter is now singular, you may only perform assignment on it, // there is no way in general to determine whether it is singular or not 

通常你通过检查它是否与end()不同,来testing它

 if (it != container.end()) { // then dereference } 

而且,使用exception处理来替代逻辑在devise和性能方面是不好的。 你的问题是非常好的,它是绝对值得替代你的代码。 exception处理像名称说只能用于罕见的意外问题。

非可移植的答案:是的 – 在Visual Studio中

Visual Studio的STL迭代器有一个“debugging”模式,正是这样做。 您不希望在发货版本中启用此function(有开销),但在检查的版本中有用。

在这里阅读关于它的VC10(这个系统可以,实际上确实会改变每个版本,所以find你的版本特定的文档)。

编辑此外,我应该补充:Visual Studio中的debugging迭代器被devise为在您使用它们时立即爆炸(而不是未定义的行为); 不允许“查询”他们的状态。

尝试和捕捉是不安全的,如果你的迭代器是“越界”,你不会,或者至less很less抛出。

什么alemjerus说,一个迭代器总是可以解除引用。 不pipe下面有什么丑陋之处。 很有可能迭代到其他内存区域,并写入其他可能保留其他对象的区域。 我一直在看代码,看variables没有什么特别的原因。 这是一个真正难以察觉的错误。

另外,明智的做法是插入和移除元素可能会使所有引用,指针和迭代器无效。

我最好的build议是让迭代器处于控制之下,并始终保持一个“结束”迭代器,以便能够testing您是否处于“行末”。

有没有什么办法来检查一个迭代器(无论是从vector,列表,双向…)是否(仍然)无法引用,即没有失效?

不,没有。 相反,您需要在存在迭代器的同时控制对容器的访问,例如:

  • 你的线程不应该修改容器(使迭代器无效),而它仍然使用该容器的实例化迭代器

  • 如果在线程迭代的时候有其他线程可能修改容器的风险,那么为了使这个场景线程安全,你的线程必须在容器上获得某种locking(这样可以防止其他线程修改容器它使用一个迭代器)

像捕捉exception的解决方法将无法正常工作。

这是一个更一般问题的特定实例,“我可以testing/检测一个指针是否有效吗?”,答案通常是“不,你不能testing它:而是你必须pipe理所有的内存分配和删除,以知道是否有任何给定的指针仍然有效“。

 if (iterator != container.end()) { iterator is dereferencable ! } 

如果你的迭代器不等于container.end() ,并且不可取,那么你做错了什么。

在一些STL容器中,当你擦除迭代器的当前值时,当前迭代器将变为无效。 发生这种情况是因为擦除操作会更改容器的内部内存结构,并将现有迭代器点上的运算符递增到未定义的位置。

在执行以下操作时,迭代器在传递到擦除函数之前会被触发。

if (something) l.erase(itd++);

任何标准容器的擦除函数的参数types(就像你在问题中列出的那样,即它是否来自向量,列表,双向…) 始终 只是这个容器的迭代器。

这个函数使用第一个给定的迭代器从容器中排除这个迭代器指向的元素,甚至是那些随后的元素。 一些容器只为一个迭代器擦除一个元素,而另外一些容器则将一个迭代器(包括此迭代器指向的元素)之后的所有元素擦除到容器的末尾。 如果擦除函数接收到两个迭代器,那么每个迭代器指向的两个元素将从容器中擦除,并且它们之间的所有其余部分也将从容器中擦除, 但重点是每个传递给擦除的迭代器任何std容器的function变得无效! 另外

指向已从容器中删除的某个元素的每个迭代器都将失效,但不会传递容器的末尾!

这意味着指向已经从容器擦除的某个元素的迭代器不能与container.end()进行比较。 这个迭代器是无效的,所以它是不可取的,也就是说你不能使用*和 – >运算符,它也不能递增,也就是说你不能使用++运算符,也不能递减,也就是说你不能使用运营商。

这也没有可比性! IE浏览器甚至不能使用==和!=运算符

实际上,你不能使用任何在std迭代器中声明和定义的运算符。 你不能对这个迭代器做任何事情,比如空指针。

用一个无效的迭代器做一些事情会立即停止程序,甚至会导致程序崩溃,并出现断言对话窗口。 无论您select什么选项,您点击了哪些button,都无法继续执行程序。 您只需单击“中止”button即可终止程序和过程。

除非您可以将其设置为容器的开始位置,或者只是忽略它,否则不会执行任何其他无效的迭代器。

但在决定如何处理迭代器之前,首先必须知道该迭代器是否无效,如果调用正在使用的容器的擦除function。

我自己做了一个函数,它检查,testing,知道并返回给定的迭代器是否无效。 您可以使用memcpy函数获取任何对象,项目,结构,类等的状态,当然我们始终使用memset函数清除或清空新的缓冲区,结构体,类或任何对象或项目:

 bool IsNull(list<int>::iterator& i) //In your example, you have used list<int>, but if your container is not list, then you have to change this parameter to the type of the container you are using, if it is either a vector or deque, and also the type of the element inside the container if necessary. { byte buffer[sizeof(i)]; memset(buffer, 0, sizeof(i)); memcpy(buffer, &i, sizeof(i)); return *buffer == 0; //I found that the size of any iterator is 12 bytes long. I also found that if the first byte of the iterator that I copy to the buffer is zero, then the iterator is invalid. Otherwise it is valid. I like to call invalid iterators also as "null iterators". } 

在我发布之前,我已经testing过这个函数,发现这个函数对我有用。

我非常希望我已经完全回答你的问题,也非常帮助你!

有什么办法来检查一个迭代器是否可以取消

是的,使用gcc debugging容器作为GNU扩展。 对于std::list您可以使用__gnu_debug::list 。 下面的代码会在尝试使用无效迭代器时立即中止。 由于debugging容器会带来额外的开销,因此只能在debugging时使用。

 #include <debug/list> int main() { __gnu_debug::list<int> l; for (int i = 1; i < 10; i++) { l.push_back(i * 10); } auto itd = l.begin(); itd++; l.erase(itd); /* now, in other place.. check if itd points to somewhere meaningful */ if (itd != l.end()) { // blablabla } } $ ./a.out /usr/include/c++/7/debug/safe_iterator.h:552: Error: attempt to compare a singular iterator to a past-the-end iterator. Objects involved in the operation: iterator "lhs" @ 0x0x7ffda4c57fc0 { type = __gnu_debug::_Safe_iterator<std::_List_iterator<int>, std::__debug::list<int, std::allocator<int> > > (mutable iterator); state = singular; references sequence with type 'std::__debug::list<int, std::allocator<int> >' @ 0x0x7ffda4c57ff0 } iterator "rhs" @ 0x0x7ffda4c580c0 { type = __gnu_debug::_Safe_iterator<std::_List_iterator<int>, std::__debug::list<int, std::allocator<int> > > (mutable iterator); state = past-the-end; references sequence with type 'std::__debug::list<int, std::allocator<int> >' @ 0x0x7ffda4c57ff0 } Aborted (core dumped) 

使用增量擦除:

    if(something)l.erase(itd ++);

所以你可以testing迭代器的有效性。