Является ли поведение std::distance
undefined при вызове пары std::vector
итераторов, которые были аннулированы перемещением vector
?
Если итераторы действительны до move, они останутся действительными после перемещения - поэтому вам не нужно пересчитывать их, используя std::distance
.
( выделено мной ниже )
std :: vector :: vector
После построения перемещения контейнера ссылки, указатели, и итераторы (кроме конечного итератора) в other
остаются действительными, но обращайтесь к элементам, которые сейчас находятся в *this
.
Текущий стандарт делает эту гарантию через выражение blanket в [container.requirements.general / 12] и более прямую гарантию находится на рассмотрении через LWG 2321 .
[container.requirements.general / 12] заявляет, что
Если не указано иное задано (явно или путем определения функции в терминах других функций), вызывая функция-член контейнера или передача контейнера в качестве аргумента библиотечной функции не должна аннулировать итераторы для или изменять значения объектов в этом контейнере.
То же самое одеяло относится к оператору присваивания перемещения, и это означает, что в соответствии со стандартом итераторы будут оставаться действительными после перемещения.
Текущая формулировка в LWG 2321 дает намек на то, как мог бы выглядеть новый параграф в стандарте, если бы рабочая группа библиотеки доработала его - что, кажется, сложно. LWG 2321 был открыт еще в 2013 году.
конструктор перемещения (или оператор присваивания перемещения, когда allocator_traits<allocator_type>::propagate_on_container_move_assignment::value
равен true
) контейнера (кроме array
) делает недействительными любые ссылки, указатели, или итераторы, относящиеся к элементам исходного контейнера. [ Примечание: Итератор end()
не ссылается ни на один элемент, поэтому он может быть признан недействительным. - конец примечания ]
Если это слишком расплывчато, вы можете использовать
[container.requirements.general / 11.6]
no swap()
функция аннулирует любые ссылки, указатели, или итераторы , относящиеся к элементам заменяемых контейнеров. [Примечание: итератор end()
не ссылается ни на один элемент, поэтому он может быть признан недействительным. - конец примечания]
Если итераторы действительны до you 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;
};