Является ли поведение std::distance
неопределенным при вызове пары итераторов std::vector
, которые были признаны недействительными при перемещении vector
?
Если итераторы действительны до перемещения, они останутся действительными и после перемещения, поэтому вам не нужно пересчитывать их с помощью std::distance
.
(выделено мной ниже)
std::vector::vector
После перемещения конструкции контейнера ссылки, указатели и итераторы и итераторы (кроме конечного итератора) в other
остаются действительными, но относятся к элементам, которые теперь находятся в *this
.
Текущий стандарт делает эту гарантию с помощью общего заявления в [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]
ни одна из функций 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;
};
person
Ted Lyngmo
schedule
16.06.2020
std::swap
другой случай. - person tsuki   schedule 16.06.2020