为何std::vector的swap会使end()迭代器失效?设计原理是什么?
结论:cppreference的说法是正确的
虽然你在C++20规范的vector::swap条目里没找到直接说明,但这个结论可以从vector的迭代器有效性规则和swap的底层行为推导出来。
为什么swap会让原end()迭代器失效?
vector的swap是O(1)时间复杂度的操作,本质只是交换两个容器内部的三个核心指针:
- 指向数据起始位置的指针
- 指向最后一个元素后位置的指针(也就是容器内部的
finish指针,对应end()返回的迭代器) - 指向容量末尾的指针
对于使用默认分配器的vector,迭代器通常就是原生指针。举个例子:
假设我们有vecA和vecB,swap前vecA.end()返回的是指向vecA内部finish位置的指针。swap完成后,vecA的finish指针被替换成了vecB原来的finish指针,但你之前获取的vecA.end()迭代器仍然指向swap前vecA的finish位置——这个位置现在属于vecB的内存空间,不再是vecA当前元素范围的一部分,因此这个迭代器对swap后的vecA来说已经失效。
设计原理:为性能妥协的选择
这种设计完全是为了保证vector的核心性能:
如果要让swap后的原end()迭代器仍然“有效”(比如原vecA.end()在swap后自动变成vecB.end()),那么迭代器就不能是简单的原生指针,必须额外携带指向所属容器的引用/指针,来跟踪容器状态的变化。这会直接导致迭代器体积变大、操作开销增加,违背了vector迭代器要尽可能接近原生指针效率的设计目标。
标准库优先保证容器核心操作的极致性能,因此选择让迭代器在swap后与原容器解绑:swap前获取的迭代器、指针、引用仍然指向原来的元素,但这些元素现在属于另一个容器——也就是说,它们对另一个容器是有效的,但对原容器来说已经失效。
需要明确的是:swap后新容器的end()(比如swap后的vecA.end())是完全有效的,失效的只是swap前从原容器获取的end()迭代器,它们不再对应当前容器的元素范围末尾。
内容的提问来源于stack exchange,提问作者user3188445

