Std::string_view и std::string в интерфейсе библиотеки утилит

Std::string_view и std::string в интерфейсе библиотеки утилит
Std::string_view и std::string в интерфейсе библиотеки утилит - aditya1702 @ Unsplash

У нас есть несколько средних и крупных программных проектов, ориентированных на разные платформы (arm32/64 и x86/amd64 на Linux и Windows), в которых много дублирующегося кода, так как у каждого проекта есть свои split(string, delimiter), find_files(regex/pattern) и тому подобное.

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

Теперь к самой проблеме. В настоящее время библиотека string предоставляет множество функций, принимающих std::string в качестве параметров и возвращающих std::string (или контейнеры, содержащие их). Я хотел бы заменить их на std::string_view там, где это необходимо. Но я не уверен, где это будет уместно и как это сделать.

Функции типа

std::vector<std::string> split(const std::string& str, char delimiter);

могут быть

std::vector<std::string_view> split(std::string_view str, char delimiter);

Параметр std::string_view здесь имеет смысл, но возвращаемый тип заставит вызывающие стороны обрабатывать его по-разному, что усложнит задачу, если вызывающая сторона захочет сохранить результаты (т.е. ей понадобится std::string).

Имеет ли смысл предоставлять несколько вариантов типа

std::vector<std::string> split(std::string_view str, char delimiter);
std::vector<std::string_view> split_v(std::string_view str, char delimiter);

?

Что должно быть по умолчанию? (т.е. будет ли более логичным, если split возвращает string_view, а split_s возвращает string?). Или есть совершенно другой способ? Какой подход был бы хорошим в целом, как с точки зрения производительности, так и простоты использования (и, следовательно, принятия), а также затруднения злоупотребления?

В C++ и его стандартных библиотеках вы найдете множество "строкоподобных" типов, таких как std::string, std::string_view, std::wstring, char *, std::string_view и так далее. Эта старая запись в блоге от 2008 года уже упоминала 30 типов (в контексте Windows legacy, но без std::vector<std::string_view>, который является C++17). Я уверен, что с тех пор это число увеличилось в несколько раз.

Как это поможет нам решить вашу проблему? Ну, в ситуации с огромным количеством доступных типов строк, я думаю, что при проектировании функций общего назначения лучше всего сосредоточиться только на одном типе, до тех пор пока

  • это имеет смысл
  • и это не приводит к огромному влиянию на производительность.

Поэтому я бы рекомендовал начать с _sv в качестве возвращаемого типа.

Это дает вызывающей стороне свободу в явном преобразовании к другому строкоподобному типу, или нет, или позволяет добавить дополнительную вспомогательную функцию (функции). Для них дополнительное дополнение, дополнительный суффикс типа _strview или std::string должен быть абсолютно приемлемым для имени дополнительных функций.

Конечно, когда выяснится, что в вашей системе конкретный вариант "split-stringview-with-conversion-to-string" нужен тысячу раз, а "split-stringview-without-conversion" нет нигде во всей кодовой базе, вы можете принять другое решение.


LetsCodeIt, 4 января 2023 г., 02:51