Std:: list - являются ли итераторы недействительными при переходе?

std::list Итераторы имеют некоторые очень приятные свойства - они остаются действительными, когда удаляется любой другой элемент, когда добавляется новый элемент и даже когда 2 списка заменяются (Правила аннулирования Iterator)!

Учитывая поведение кода и что итераторы реализуются по форме указателя на фактический node, который не изменяется при перемещении списка, я предполагаю, что итераторы все еще действительны в новом контейнере, когда std::list перемещается, но также я могу находиться в области UB здесь, обращаясь к недействительной памяти, которая на самом деле имеет "ожидаемое" значение.

std::list<int> l1{3, 2, 1};
std::list<int> l2;

auto it = std::prev(l1.end());
std::cout<<l1.size()<<" "<<l2.size()<<" "<<*it<<std::endl;

l2 = std::move(l1);
std::cout<<l2.size()<<" "<<*it<<std::endl;

3 0 1
3 1

Гарантируется ли это стандартом, если итераторы остаются действительными при перемещении std::list? Как насчет других контейнеров?

Ответ 1

Для контейнеров в целом только swap гарантирует, что итераторы остаются в силе (и указывают на замененные контейнеры).

Для std::list специальная функция-член splice() гарантирует, что итераторы сохраняют ожидаемое значение.

В целом, построение контейнера из rvalue не дает гарантий относительно итераторов; единственным общим требованием является то, что новый контейнер имеет "то же значение", что и исходный контейнер, из которого он был построен.

(Вы можете представить себе отладочные реализации итератора, которые хранят ссылку на контейнер, и эта ссылка станет болтаться после перемещения.)