检查迭代器是否有效

huf*_*uff 63 c++ iterator stl dereference

有没有办法检查迭代器(无论是来自向量,列表,双端队列......)是否(仍)可解除引用,即未被无效?

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

示例:(不起作用)

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
}
Run Code Online (Sandbox Code Playgroud)

小智 61

我假设你的意思是"迭代器是有效的",它由于容器的更改而没有失效(例如,插入/擦除向量).在这种情况下,不,您无法确定迭代器是否(安全地)可解除引用.

  • 虽然,我认为现在是时候将`Checked STL`引入到争论中:一个检查的stl目标是捕获迭代器错误>使用无效迭代器或比较来自不同容器的迭代器等.通过检查stl的旅行绝对应该是您的测试套件的一部分;) (5认同)
  • @Ajeet:已检查的STL已经存在,通常在传统的STL中出现但是`#ifdef`已经出现.它确实花费了成本,减慢了代码,但MSVC例如有2级检查,第一级非常容易访问(第二种肯定很慢......)**请记住这显然只适用于**测试**构建. (4认同)
  • 好吧,C++ SL精确地记录每个容器成员函数,无论它是否使迭代器无效.就此而言,你不能_check_但你可以_know_. (2认同)

ava*_*kar 25

正如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
Run Code Online (Sandbox Code Playgroud)


Ter*_*fey 10

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

Visual Studio的STL迭代器具有"调试"模式,正是这样做的.您不希望在发布版本中启用此功能(存在开销),但在已检查的版本中非常有用.

阅读关于它的VC10 这里(该系统能在事实上的确改变了每一个版本,所以查找特定于您的版本的文档).

编辑此外,我应该补充:Visual Studio中的调试迭代器被设计为在您使用它们时立即爆炸(而不是未定义的行为); 不允许"查询"他们的国家.

  • 作为这个答案的附录,LLVM 12.0 版提供了一个[调试模式](https://libcxx.llvm.org/docs/DesignDocs/DebugMode.html),可以提供类似的调试功能。它是通过使用“_LIBCPP_DEBUG”宏来启用的。旧版本的 LLVM(如 11)似乎也支持此功能。然而,该宏的必要数字设置似乎取决于 LLVM 版本。 (2认同)

jde*_*aan 9

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

if (it != container.end())
{
   // then dereference
}
Run Code Online (Sandbox Code Playgroud)

此外,在设计和性能方面使用异常处理来替换逻辑是不好的.您的问题非常好,在您的代码中绝对值得替换.名称之类的异常处理仅用于罕见的意外问题.

  • 那么,当你破坏迭代器在列表中指向的元素,或者位于向量之前的元素时,迭代器会指向结尾?在我的情况下,我没有...(我将编辑问题更清楚) (2认同)

Chr*_*isW 7

有没有办法检查迭代器(无论是来自向量,列表,双端队列......)是否(仍)可解除引用,即尚未失效?

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

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

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

像捕获异常这样的解决方法是行不通的.

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