Что такое string_view?

string_view была предложена в рамках технического обслуживания по основам библиотеки C++(N3921) добавлен в C++17

Насколько я понимаю, это тип, который представляет собой некую строковую «концепцию», которая представляет собой представление любого типа контейнера, в котором может храниться что-то видимое в виде строки.

  • Это правильно ?
  • Должен ли канонический тип параметра const std::string& стать string_view ?
  • Есть ли еще один важный момент, связанный с string_view, который следует принять во внимание?

person Drax    schedule 27.12.2013    source источник
comment
Наконец, кто-то понимает, что строкам нужна другая семантика, хотя введение string_view — это всего лишь небольшой шаг.   -  person John Z. Li    schedule 31.08.2018


Ответы (2)


Цель любых и всех видов предложений «ссылка на строку» и «ссылка на массив» состоит в том, чтобы избежать копирования данных, которые уже принадлежат где-то еще и для которых требуется только неизменяемое представление. Рассматриваемый string_view является одним из таких предложений; были и более ранние, которые назывались string_ref и array_ref.

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

Такой класс дескриптора представления можно было бы дешево передавать по значению и предлагать дешевые операции подстроки (которые могут быть реализованы как простое приращение указателя и корректировка размера).

Многие варианты использования строк не требуют фактического владения строками, и рассматриваемая строка часто уже принадлежит кому-то другому. Таким образом, существует реальный потенциал для повышения эффективности за счет исключения ненужных копий (подумайте обо всех распределениях и исключениях, которые вы можете сохранить).

Исходные строки C страдали от проблемы, заключавшейся в том, что нулевой терминатор был частью API-интерфейсов строк, и поэтому вы не могли легко создавать подстроки без изменения базовой строки (а-ля strtok). В C++ это легко решается путем хранения длины отдельно и переноса указателя и размера в один класс.

Единственное серьезное препятствие и расхождение с философией стандартной библиотеки C++, о котором я могу думать, заключается в том, что такие классы "ссылочного представления" имеют совершенно другую семантику владения, чем остальная часть стандартной библиотеки. В принципе, все остальное в стандартной библиотеке безусловно безопасно и правильно (если компилируется, то правильно). С такими эталонными классами это уже не так. Корректность вашей программы зависит от окружающего кода, который использует эти классы. Так что это сложнее проверить и научить.

person Kerrek SB    schedule 27.12.2013
comment
Корабль плыл по этой философии с reference_wrapper, не так ли? - person Steve Jessop; 27.12.2013
comment
@KerrekSB Боюсь, я не понимаю. Не могли бы вы уточнить, что такие ссылочные классы представления имеют совершенно другую семантику владения, чем остальная часть стандартной библиотеки, пожалуйста? Мне непонятно: Чем это отличается от оборванных ссылок/указателей? Или недействительные итераторы из-за вставки (например, std::vector)? У нас уже есть эти проблемы, для меня очень естественно, что представление без владения будет иметь те же проблемы, что и указатели/ссылки/итераторы без владения. - person Ali; 27.12.2013
comment
@SteveJessop: Да :-) Я почти собирался включить это. Я предполагаю, что использование эталонных оберток довольно ограничено, но это правильное замечание. - person Kerrek SB; 27.12.2013
comment
@Ali: Когда вы используете любой другой контейнер стандартной библиотеки, вы можете подтвердить правильность кода, просто взглянув на код, который использует контейнер. Не так для string_view. (Я не говорил, что вы никогда не сможете написать неработающий код. Просто неисправность локальна.) - person Kerrek SB; 27.12.2013
comment
@KerrekSB Хорошо, спасибо за разъяснение. Проголосовал за ваш ответ! - person Ali; 27.12.2013
comment
@KerrekSB Хорошо, так что в основном он представляет собой объект, который может выполнять операции только для чтения со строкой с меньшими затратами на производительность. Почему-то это выглядит как std::weak_ptr, но я предполагаю, что какая-то функция-член lock для безопасного доступа сведет на нет все точки прироста производительности. В любом случае, валидность const std::string& уже привязана к исходной строке, если вы ее не скопируете, так что на самом деле ничего не потеряно. - person Drax; 28.12.2013
comment
@Drax: подумайте также о ситуациях, когда вы передаете строковый литерал. Если бы аргумент функции был const string &, вам пришлось бы создать дорогостоящее временное исключение. При строковом представлении ничего не нужно копировать или выделять. - person Kerrek SB; 28.12.2013
comment
@KerrekSB Действительно! Как вы думаете, это будет какой-то конструктор constexpr для инициализации из литералов или другой string_view, чтобы их можно было использовать в качестве строковых констант по умолчанию без непредсказуемой инициализации статического порядка? - person Drax; 28.12.2013
comment
@Drax: я уверен, что над этим работают; Я не уверен, что что-то из этого войдет в следующий стандарт. Строковые литералы странные; вы не можете отличить их от массивов. - person Kerrek SB; 28.12.2013
comment
На ум приходят итераторы. (На самом деле часть работы по стандартизации, выполняемой для string_view и т. д., включает в себя проверку того, что это будет хорошо работать в диапазонах — имея в виду, что пара итераторов вполне может быть моделью диапазона, в зависимости от деталей.) Не говоря уже о auto uhoh = [] { return { 1, 2, 3, 4, 5 }; }(); - person Luc Danton; 30.12.2013
comment
@LucDanton: Брр. Что за тип uhoh?? - person Kerrek SB; 30.12.2013
comment
Я удивлен, что они не выбрали std::range из boost::iterator_range - IMO это лучше, чем идея string_view - person Charles Salvia; 04.06.2015
comment
Я не вижу смысла делать представление немутирующим. Просто сделайте его изменяемым по умолчанию и добавьте const, если это необходимо, например string_span, в ГСЛ. - person nwp; 09.12.2015
comment
@nwp: Многие люди и языки стали оплакивать ужасные значения по умолчанию C ++ и думать, что const и unshared должны быть значениями по умолчанию, с изменяемыми и общими явными, редкими исключениями. - person Kerrek SB; 09.12.2015
comment
@KerrekSB Я согласен с этими людьми, но если вы не перепишете C ++ с const по умолчанию, чтобы он был перезаписан mutable, представление не должно быть по умолчанию const. - person nwp; 09.12.2015
comment
Вы должны с чего-то начать? - person ruipacheco; 25.01.2016
comment
Это больше похоже на строковое представление, чем на это. Он также может обрабатывать строки времени компиляции, включая хэширование строк времени компиляции. - person Viktor Sehr; 07.05.2016
comment
@ruipacheco Возможно, но согласованность важнее всего, особенно потому, что С++ никогда не будет переписан с const по умолчанию, поэтому то, что вы начинаете, никогда не будет завершено, и за счет несогласованности, которой никогда не будет решено. - person Lightness Races in Orbit; 12.10.2018
comment
@LightnessRacesinOrbit: C++ никогда не будет переписан с const по умолчанию — я думал, что это называется Rust? - person Kevin; 04.06.2019
comment
@Кевин Ну точно: D - person Lightness Races in Orbit; 04.06.2019
comment
Но в чем преимущество перед const std::string& ? - person peterflynn; 14.04.2020
comment
@peterflynn: Если ваш аргумент является, скажем, строковым литералом, то параметр const std::string& потребует динамического выделения и копирования, а строковое представление — нет. - person Kerrek SB; 16.04.2020

(Обучаюсь в 2021 г.)

Из ‹string_view›:

Семейство специализаций шаблонов string_view обеспечивает эффективный способ передачи доступного только для чтения, защищенного от исключений и не принадлежащего владельцу дескриптора символьных данных любых строкоподобных объектов с первым элементом последовательности в нулевой позиции. (...)

Из блога команды Microsoft C++ std::string_view: Клейкая лента струнных типов от 21 августа 2018 г. (данные получены 1 апреля 2021 г.):

string_view решает проблему «каждая платформа и библиотека имеет свой собственный строковый тип» для параметров. Он может привязываться к любой последовательности символов, поэтому вы можете просто написать свою функцию, принимающую строковое представление:

void f(wstring_view); // string_view that uses wchar_t's

и вызовите его, не заботясь о том, какой строковый тип использует вызывающий код (и › для пар аргументов (char*, length) просто добавьте {} вокруг них) (...)

(...)

Сегодня наиболее распространенным «наименьшим общим знаменателем», используемым для передачи строковых данных, является строка с завершающим нулем (или, как это называется в стандарте, последовательность символов с нулевым завершением). Это было с нами задолго до появления C++ и обеспечивало чистое взаимодействие на «плоском C». Однако char* и его вспомогательная библиотека связаны с кодом, который можно использовать, поскольку информация о длине является внутренним свойством данных и может быть изменена. Кроме того, нуль, используемый для ограничения длины, запрещает встроенные нули и приводит к тому, что одна из наиболее распространенных строковых операций, запрашивающая длину, становится линейной по длине строки.

(...)

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

person tymtam    schedule 01.04.2021