考虑下面的代码
void foo( bool forwad )
{
vector<MyObject>::iterator it, end_it;
int dir;
it = some_global_vector.begin() + some_position;
if( forward )
{
dir = 1;
it += 1;
end_it = some_global_vector.end();
}
else
{
dir = -1;
it -= 1;
end_it = some_global_vector.begin()-1;
}
while( it != end_it )
{
if( do_domething() )
break;
it += dir;
}
}
正如你所看到的,当
forward == false
时存在一些疑问,因为 begin()
存在减法,而迭代器 it
当它指向 begin()
时可以被减去。在我不取消引用这个坏指向迭代器之前,我找不到任何地方是否可以。
编辑
我阅读了 ISO C++ 标准并得到了一些结论。 没有承诺
vector::begin()
不能在内部指向地址 0
处的内存,我认为这就是结束,但所有容器都依赖于标准分配器。该分配器取决于 new
运算符。而且,没有任何信息表明new
永远不会返回0
。但标准分配器还取决于 delete
运算符,如果您通过 0
,该运算符应该不执行任何操作。因此,根据这个事实,new
无法返回0
,因为无法删除该指针,因此,非空vector
无法返回指向begin()
的0
。
结论:
如果上面是指向
vector::begin()
的右减迭代器应该是安全的,因为 vector
的内存是连续的。
我说得对吗?
终极答案
即使它现在有效并且将来会有效,根据标准,它也是未定义的行为。如果您这样做,您将自行承担风险。请参阅此类似的问题了解更多信息。
您不能递减传递给 begin 的迭代器,也不能计算
begin() - 1
。
虽然实现需要为最后一个元素传递一个位置,但在开始之前不需要有任何可用的地址空间。所以
begin() - 1
可能不是一个有效的地址(并且绝对不是一个有效的迭代器)。
关于问题2:
尽管
if (p == 0)
测试指针是否为空,但这并不意味着空指针必须由所有位为零表示。它也可能全部为 1,或者其他。编译器的魔力无论如何都会让测试工作。
无效地址的另一个例子是,当您释放大块内存时,堆管理器也可能会从进程中删除相应的虚拟地址空间。 在释放空间之后开始的另一个内存块可能有一个地址,例如,
0x10000
,其中地址
0x10000 - 1
不再存在。某些使用指针专用地址寄存器的硬件在加载无效指针时会陷入陷阱。它只是可以检测到
0x10000 - 1
不再映射到RAM并中止你的程序。标准的编写是为了允许这样做,因为这样的硬件存在。我们并不是说这是常见桌面操作系统上通常发生的情况,而是根据语言标准可能
发生的情况。