减法或递减指向开始的随机访问迭代器

问题描述 投票:0回答:1

考虑下面的代码

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
的内存是连续的。

我说得对吗?

终极答案

即使它现在有效并且将来会有效,根据标准,它也是未定义的行为。如果您这样做,您将自行承担风险。请参阅此类似的问题了解更多信息。

c++ iterator decrement
1个回答
6
投票

您不能递减传递给 begin 的迭代器,也不能计算

begin() - 1

虽然实现需要为最后一个元素传递一个位置,但在开始之前不需要有任何可用的地址空间。所以

begin() - 1
可能不是一个有效的地址(并且绝对不是一个有效的迭代器)。


关于问题2:

尽管

if (p == 0)
测试指针是否为空,但这并不意味着空指针必须由所有位为零表示。它也可能全部为 1,或者其他。编译器的魔力无论如何都会让测试工作。

无效地址的另一个例子是,当您释放大块内存时,堆管理器也可能会从进程中删除相应的虚拟地址空间。 在释放空间之后开始的另一个内存块可能有一个地址,例如,

0x10000

,其中地址

0x10000 - 1
不再存在。某些使用指针专用地址寄存器的硬件在加载无效指针时会陷入陷阱。它只是
可以
检测到0x10000 - 1不再映射到RAM并中止你的程序。标准的编写是为了允许这样做,因为这样的硬件存在。

我们并不是说这是常见桌面操作系统上通常发生的情况,而是根据语言标准

可能

发生的情况。

© www.soinside.com 2019 - 2024. All rights reserved.