Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/164.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 检查迭代器是否有效_C++_Stl_Iterator_Dereference - Fatal编程技术网

C++ 检查迭代器是否有效

C++ 检查迭代器是否有效,c++,stl,iterator,dereference,C++,Stl,Iterator,Dereference,有没有办法检查迭代器(是否来自向量、列表、deque…)是否(仍然)可取消引用,即未失效 我一直在使用try-catch,但是有没有更直接的方法呢 示例:(这不起作用) 列表l; 对于(i=1;i通常通过检查它是否与end()不同来测试它,如 此外,在设计和性能方面,使用异常处理替换逻辑是不好的。您的问题非常好,在代码中完全值得替换。如名称所述的异常处理只能用于罕见的意外问题 if (iterator != container.end()) { iterator is dereferenc

有没有办法检查迭代器(是否来自向量、列表、deque…)是否(仍然)可取消引用,即未失效

我一直在使用
try
-
catch
,但是有没有更直接的方法呢

示例:(这不起作用)

列表l;

对于(i=1;i通常通过检查它是否与end()不同来测试它,如

此外,在设计和性能方面,使用异常处理替换逻辑是不好的。您的问题非常好,在代码中完全值得替换。如名称所述的异常处理只能用于罕见的意外问题

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

如果您的迭代器不等于container.end()
,并且不可取消引用,则表明您做了错误的事情。

尝试和捕获不安全,如果迭代器“超出范围”,则不会抛出,或者至少很少抛出

正如alemjerus所说,迭代器总是可以被取消引用的。不管下面有多么丑陋。它很有可能迭代到内存的其他区域,并写入可能保留其他对象的其他区域。我一直在查看代码,观察变量的变化,没有特殊的原因。这是一个很难检测到的错误

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


我最好的建议是让您的迭代器处于控制之下,并且始终手头有一个“end”迭代器,以便能够测试您是否处于所谓的“end of the line”。

我假定您的意思是“Isa iterator valid”,即它没有因为容器的更改而失效(例如,插入/删除向量)。在这种情况下,不,您无法确定迭代器是否(安全地)可取消引用。

正如jdehaan所说,如果迭代器未失效并指向容器,您可以将其与
容器.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
std::vector::iterator iter=vec.begin();
调整向量大小(向量容量()+1);
//iter现在是单数的,您只能对其执行赋值,
//一般来说,没有办法确定它是否是单数
是否有任何方法可以检查迭代器(是否来自向量、列表、deque…)是否(仍然)可取消引用,即未失效

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

  • 当线程仍在使用容器的实例化迭代器时,不应修改容器(使迭代器无效)

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

像捕获异常这样的变通方法是行不通的


这是一个更一般问题的具体实例,“我可以测试/检测指针是否有效吗?”,其答案通常是“不,您不能测试它:相反,您必须管理所有内存分配和删除,以便知道任何给定指针是否仍然有效。”

不可移植答案:是-在Visual Studio中

VisualStudio的STL迭代器有一个“调试”模式,可以完全做到这一点。您不希望在ship builds中启用此功能(有开销),但在checked builds中很有用

在VC10上阅读它(该系统可以而且事实上确实会更改每个版本,因此请查找特定于您的版本的文档)


编辑另外,我应该补充:visual studio中的调试迭代器设计为在使用时立即爆炸(而不是未定义的行为);不允许“查询”它们的状态。

使用带增量的擦除:

if (something) l.erase(itd++); 如果(某物)l.擦除(itd++);
因此,您可以测试迭代器的有效性。

在某些STL容器中,当您擦除迭代器的当前值时,当前迭代器将无效。这是因为擦除操作更改了容器的内部内存结构,并且现有迭代器上的增量运算符指向未定义的位置。

当您执行以下操作时,迭代器在传递给erase函数之前被激活


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

任何std容器的擦除函数的参数类型(如您在问题中所列,即它是否来自向量、列表、数据…)总是仅此容器的迭代器

此函数使用第一个给定的迭代器从容器中排除该迭代器指向的元素,甚至排除后面的元素。有些容器仅为一个迭代器擦除一个元素,而有些容器则擦除一个迭代器后面的所有元素(包括该迭代器指向的元素)如果erase函数接收到两个迭代器,则每个迭代器指向的两个元素将从容器中删除,它们之间的其余元素也将从容器中删除,但问题是,传递给任何std容器的erase函数的每个迭代器都将失效id!

指向已从容器中删除的某个元素的每个迭代器都将无效,但它不会通过容器的末尾!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
if (something) l.erase(itd++);
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".
}
#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)