我不明白为什么在重新分配时应该使vector
的迭代器失效。
仅仅通过在迭代器中存储偏移 - 而不是指针 - 来阻止这种情况吗?
为什么vector
没有这样设计?
答案 0 :(得分:15)
因为迭代器要这样做,他们需要存储一个指向矢量对象的指针。对于每次数据访问,他们需要按照指向矢量的指针,然后按照其中的指针到数据数组的当前位置,然后添加偏移量*元素大小。这会慢得多,并且size_type
成员需要更多内存。
当然,它有时是一个很好的折衷方案,如果能够在需要时选择它会很好,但它比(C风格)直接阵列使用更慢,更笨重。在引入STL时,std::vector
被无情地审查了性能,并且正常实现针对空间和速度优化了这个便利/可靠性因素,就像数组等效operator[]
和数组一样快但不如at()
安全。
答案 1 :(得分:15)
只是为与性能相关的理由添加一个引用:在设计C ++时,Stroustrup认为像std::vector这样的模板类接近本机数组的性能特征至关重要:
强调运行时效率的一个原因是我想要的 模板在时间和空间上足够有效,可用于 低级类型,如数组和列表。
...
更高级别的替代方案 - 例如,带有大小()的范围检查数组 操作,多维数组,具有适当数字的矢量类型 向量操作和复制语义等 - 将被接受 用户只有在他们的运行时,空间和符号方便的情况下 接近了内置数组。
换句话说,提供参数化类型的语言机制 应该是有关用户应该能够负担得起的 消除数组的使用,转而使用标准库类。
Bjarne Stroustrup, C ++的设计和演变,p.342。
答案 2 :(得分:5)
您可以通过包装标准std::vector<T>::iterator
来增加安全性,但不能通过包装extension::vector<T>::safe_iterator
来增加速度。这是一般原则,并解释了许多C ++设计选择。
答案 3 :(得分:3)
这些决定有很多原因。正如其他人所指出的,向量的iterator
的最基本实现是指向元素的普通指针。为了能够处理push_back
,必须修改迭代器以处理指向矢量和位置的指针,在通过运算符访问时,矢量指针将被取消引用,指向所获得数据的指针和添加位置,额外取消引用。
虽然这不是最有效的实施,但这并不是一个限制因素。 VS / Dinkumware库中的迭代器的默认实现(即使在发布中)是经过检查的迭代器,它们管理等量的信息。
实际问题伴随着其他变异操作。考虑在向量的中间插入/擦除。为了保持所有迭代器的有效性,容器必须跟踪迭代器的所有实例并调整位置字段,以便它们仍然引用相同的元素(已被插入/移除替换)。
答案 4 :(得分:1)
您需要存储偏移量和指向矢量对象本身的指针。
如指定的那样,迭代器可以只是一个指针,占用的空间更少。
答案 5 :(得分:1)
TL; DR - 因为你为非常复杂的远距离动作交易了无效的简单规则。
请注意,“存储指向矢量对象的指针”会导致新的失效案例。例如,今天swap
保留了迭代器的有效性,如果向量的指针(或引用)存储在迭代器中,它就不再可能。移动矢量元数据本身的所有操作(矢量矢量任何人?)都会使迭代器失效。
交易是“当元素的指针/引用无效时,迭代器变为无效”,“当向量的指针/引用无效时,迭代器变为无效”。
性能参数并不重要,因为提议的替代实现甚至不正确。
答案 6 :(得分:0)
我的迭代器没有失效,它是否指向相同的元素或插入之前的相同位置?换句话说,即使没有性能问题,决定使用哪种替代定义也是非常重要的。