无效迭代器上的算术

Arithmetic on invalidated iterators

本文关键字:迭代器 无效      更新时间:2023-10-16

当在一对通过移动vector而失效的std::vector迭代器上调用时,std::distance的行为是否未定义?

对于上下文: 我正在为一个类编写复制和移动构造函数,该类具有vector数据和指向该数据的迭代器vector。将数据移动到目标后,我需要转换迭代器的向量以指向新容器。我想避免在内存中创建中间索引表示形式。

在一

对通过移动vector而失效的std::vector迭代器上调用时,std::distance的行为是否未定义?

如果迭代器在移动前有效,则它们在移动后将保持有效 - 因此您无需使用std::distance重新计算它们。

(下面强调我的(

标准::矢量::矢量

在容器移动构造之后,引用、指针和迭代器(结束迭代器除外(other仍然有效,但引用现在*this中的元素。

当前标准通过 [container.requirements.general/12] 中的一揽子声明做出此保证,并且正在考虑通过 LWG 2321 提供更直接的保证。

[container.requirements.general/12] 指出

除非另有指定(显式或通过根据其他函数定义函数(,否则调用容器成员函数或将容器作为参数传递给库函数不应使该容器中的对象的迭代器无效或更改其值。

相同的一揽子语句适用于移动赋值运算符,这意味着,根据标准,迭代器将在移动后保持有效。

LWG 2321 中的当前措辞暗示了如果图书馆工作组最终确定这一点,标准中的新段落会是什么样子——这似乎很难。LWG 2321 于 2013 年开业。

容器(array除外(的任何移动构造函数(或allocator_traits<allocator_type>::propagate_on_container_move_assignment::valuetrue时的移动赋值运算符(都不会使引用源容器元素的任何引用、指针或迭代器无效。[注意:end()迭代器不引用任何元素,因此它可能无效。

如果这太模糊,您可以使用

[容器.要求.常规/11.6]

没有swap()函数会使引用要交换的容器元素的任何引用、指针或迭代器失效。[注意:end()迭代器不引用任何元素,因此它可能无效。

如果迭代器在您swap之前有效,则它们在swap之后有效。

下面是一个使用swap保证的示例类:

#include <vector>
class Foo {
std::vector<int> data{};
std::vector<decltype(data)::iterator> dits{};
public:
Foo() = default;
Foo(const Foo&) = delete;    // here, dits would need to be calculated
// A move constructor guaranteed to preserve iterator validity.
Foo(Foo&& rhs) noexcept {
data.swap(rhs.data);
dits.swap(rhs.dits);
}
Foo& operator=(const Foo&) = delete;
// A move assignment operator guaranteed to preserve iterator validity.
Foo& operator=(Foo&& rhs) noexcept {
data.swap(rhs.data);
dits.swap(rhs.dits);
return *this;
}
~Foo() = default;
};