减法或减法随机访问迭代器指向开始
考虑下面的代码
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()
时被减去.如果可以的话,我找不到任何地方,直到我不取消引用这个错误的指向迭代器).
As you can see there is some doubt when forward == false
becouse there is an substraction from begin()
and iterator it
can be substracted when it points at begin()
. I can't find anywhere if it is ok until I not dereference this bad pointing iterator).
编辑
我阅读了 ISO C++ 标准并得出了一些结论.没有保证 vector::begin()
不能内部指向地址 0
处的内存,我在想它是结束,但所有容器都依赖在标准分配器上.这个分配器依赖于 new
操作符.而且,没有信息表明 new
永远不会返回 0
.但是标准分配器也依赖于 delete
操作符,如果你传递 0
,这个操作符应该什么也不做.因此,根据这个事实, new
不能返回 0
因为没有办法删除该指针,因此,非空 vector
无法返回指向 0
的 begin()
.
I read ISO C++ Standard and have some conclusions.
There is no promise that vector::begin()
can't internaly point to memory at adress 0
, and I was thinking that It is the end, but all containers depend on standard alocator. This alocator depends on new
operator. And also, there is no information that new
will never return 0
. But standard alocator depends also on delete
operator and this operator is supose to do nothing if you pass 0
. So by this fact, new
can't return 0
becouse there will be no way to delete that pointer, and by that, non empty vector
can't return begin()
that points to 0
.
结论:
如果上面是指向 vector::begin()
的右递减插入器应该是安全的,因为 vector
的内部存储器是连续的.
If above is right decrementing interator that points at vector::begin()
should be safe, since internal memory of the vector
is continouse.
我说的对吗?
终极答案
即使它现在有效并且将来会有效,根据标准,它也是未定义的行为.如果您这样做,您将自行承担风险.看到这个类似的问题更多信息.
Even if it works now and will be working in the future it is undefined behavour according to the standard. If you do this, you are doing this on your own risk. See this simmilar question for more informations.
推荐答案
你不能递减传递给 begin 的迭代器,也不能计算 begin() - 1
.
You cannot decrement an iterator passed begin, or compute begin() - 1
.
虽然实现需要有一个通过最后一个元素的位置,但在开始之前不需要有任何可用的地址空间.所以 begin() - 1
可能不是一个有效的地址(而且绝对不是一个有效的迭代器).
While the implementation is required to have a position for one passed the last element, it is not required to have any address space available before begin. So begin() - 1
might not be a valid address (and definitely not a valid iterator).
关于第 2 题:
尽管 if (p == 0)
测试指针是否为空,但这并不意味着空指针必须由所有位为零表示.它也可以是所有位 1,或其他.无论如何,编译器魔法都会使测试工作.
Even though if (p == 0)
tests if the pointer is null, that doesn't mean that a null pointer has to be represented by all bits zero. It could also be all bits 1, or something else. Compiler magic will make the test work anyway.
另一个无效地址的例子是,当您释放一大块内存时,堆管理器可能也可能从您的进程中删除相应的虚拟地址空间.
Another example of an invalid address is that when you deallocate a large block of memory, the heap manager just could possibly also remove the corresponding virtual address space from your process.
在释放空间之后开始的另一个内存块可能有一个地址,例如 0x10000
,其中地址 0x10000 - 1
不再存在.某些硬件使用专用地址寄存器作为指针,在加载无效指针时会陷入陷阱.它只是可以检测到 0x10000 - 1
不再映射到 RAM 并中止您的程序.编写标准是为了允许这样做,因为存在这样的硬件.
Another memory block starting just after the deallocated space could then have an address, say, 0x10000
where the address 0x10000 - 1
does no longer exist. Some hardware, which uses dedicated address registers for pointers, is known to trap when loading an invalid pointer. It just could detect that 0x10000 - 1
isn't mapped to RAM anymore and abort your program. The standard is written to allow this, because such hardware exists.
我们并不是说这是常见桌面操作系统上通常会发生的情况,而是根据语言标准可能发生的情况.
We don't say that this is what normally happens on common desktop operating systems, just what could happen according to the language standard.
相关文章