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