В своей компании я провел молниеносную беседу о новом (C ++ 17) интерфейсе сращивания ассоциативных контейнеров.Я продемонстрировал std::set::extract
, а затем спросил, что будет с итераторами и указателями на извлеченный элемент.Они поймали меня не на той ноге, и я не смог ответить на вопрос, но посмотрел его сразу после выступления.
[associative.reqmts] 21.2.6.10 в текущем проекте стандартагласит:
extract
члены делают недействительными только итераторы для удаленного элемента;указатели и ссылки на удаленный элемент остаются действительными. Однако доступ к элементу через такие указатели и ссылки, когда элемент принадлежит node_type
, является неопределенным поведением. Ссылки и указатели на элемент, полученный, когда он принадлежит node_type
, становятся недействительными, еслиэлемент успешно вставлен.
(предложение P0083R3 уже содержит эту формулировку)
Теперь выделенная часть действительно меня смущает.Я понимаю концепцию действительного, но не разыменованного указателя (nullptr
) или итератора (конечный итератор).Я нашел «определение» действительных указателей от David Vandevoorde и узнал, что существуют также действительные, но не разыменовываемые указатели, которые не являются nullptr
.(а именно указатель один за существующим объектом)
При всем этом моя ментальная модель происходящего выглядит следующим образом:
- Получается указатель на элемент в наборе,поэтому указатель действителен.Разыменование этого указателя определено и дает доступ к элементу в наборе.
- Теперь один и тот же элемент извлекается из набора.Концептуально элемент не копируется, не перемещается и не изменяется иным образом, связанный с ним узел просто удаляется из внутреннего дерева, с которым
set
управляет его данными.Оставшееся дерево, возможно, потребуется перебалансировать.Возвращенный node_handle
становится владельцем узла потерянного дерева.
Как и в стандарте, указатель, полученный в 1), остается действительным и не может быть изменен на extract
, так что это также поддерживает эту ментальную модель,Однако в этой модели нет причин, по которым разыменование указателя внезапно будет неопределенным.Следовательно, с g ++ на coliru он работает так, как я и ожидал .(это никоим образом не является доказательством)
Слабость, которую стандарт дает разработчикам библиотек, кажется излишне большой.Чего мне не хватает?Я только вижу, что при извлечении их константа заданных значений отбрасывается, но я не понимаю, как это могло бы повлиять.
То же рассуждение применимо к случаю вставки, упомянутому в последнем цитируемом предложении.