Для чего нужен std :: contiguous_iterator? - PullRequest
4 голосов
/ 08 марта 2020

Для каких целей я могу его использовать? Почему это лучше, чем random_access_iterator? Есть ли какое-то преимущество, если я его использую?

Ответы [ 4 ]

4 голосов
/ 08 марта 2020

В C ++ 17 нет такой вещи, как std::contiguous_iterator. Однако существует ContiguousIterator с именем требование . Это представляет итератор произвольного доступа для последовательности элементов, где каждый элемент хранится непрерывно, точно так же, как массив. Это означает, что при наличии указателя на value_type от итератора возможно выполнить арифметику указателя c для этого указателя, которая должна работать точно так же, как и выполнение той же арифметики c на соответствующих итераторах .

Цель этого состоит в том, чтобы обеспечить более эффективную реализацию алгоритмов на смежных итераторах. Или запретить использование алгоритмов на несмежных итераторах. Один из примеров того, где это имеет значение, - это если вы пытаетесь передать итераторы C ++ в интерфейс C, основанный на указателях на массивы. Вы можете обернуть такие интерфейсы за общие c алгоритмы, проверяя смежность итератора в шаблоне.

Или, по крайней мере, теоретически; в C ++ 17 это было на самом деле невозможно .. Причина в том, что на самом деле не было способа проверить, является ли итератор ContiguousIterator. Нет способа спросить указатель, если выполнение арифметики указателя c для указателя на элемент из итератора допустимо. И не было std::contiguous_iterator_category, которое можно было бы использовать для таких итераторов (поскольку это могло вызвать проблемы совместимости). Таким образом, вы не можете использовать инструменты SFINAE для проверки непрерывности итератора.

C ++ 20 std::contiguous_iterator концепция решает эту проблему. Это также решает другую проблему с непрерывными итераторами. Смотрите, приведенное выше объяснение поведения ContiguousIterator начинается с того, что у нас есть указатель на элемент из диапазона. Ну, как ты это получил? Очевидным способом было бы сделать что-то вроде std::addressof(*it), но что если it является конечным итератором? Конечный итератор не поддерживает разыменование, поэтому вы не можете этого сделать. В принципе, даже если вы знаете, что итератор является смежным, как вы go конвертируете его в эквивалентный указатель?

Концепция std::contiguous_iterator решает обе эти проблемы. std::to_address доступно, что преобразует любой непрерывный итератор в эквивалентное значение указателя. И есть тег traits, который итератор должен предоставить, чтобы обозначить, что он на самом деле является смежным итератором, просто в этом случае реализация по умолчанию to_address оказывается действительной для несмежного итератора.

4 голосов
/ 08 марта 2020

Для непрерывного итератора вы можете получить указатель на элемент, на который «указывает» итератор, и использовать его как указатель на непрерывный массив.

Это не может быть гарантировано при произвольном доступе итератор.

Помните, что, например, std::deque является контейнером с произвольным доступом, но обычно это не непрерывный контейнер (в отличие от std::vector, который является как произвольным, так и непрерывным).

3 голосов
/ 08 марта 2020

Итератору с произвольным доступом требуется только постоянное время (iterator) + (offset), тогда как смежные итераторы имеют более надежную гарантию, что std::addressof(*((iterator) + (offset))) == std::addressof(*(iterator)) + (offset) (без учета перегруженных operator& с).

Это в основном означает, что итератор является указатель или легкая обертка вокруг указателя, поэтому он эквивалентен указателю на его элементы, тогда как итератор произвольного доступа может сделать больше за счет того, что он может быть громоздким и не может превратить его в простой указатель.

0 голосов
/ 08 марта 2020

Как концепция C ++ 20, я ожидаю, что вы можете использовать ее для определения другого алгоритма, если контейнер является смежным. Возможно использование кеша.

...