ideas
ideas copied to clipboard
std::string_ref как обертка над const char*
Хотелось бы иметь обертку над const char* у которой implicit конструктор от const char*, определены операторы сравнения и ряд других полезных функций. Мне кажется странным, но такого нет в библиотеке до сих пор. Может быть есть на то какие-то причины. Хотелось бы обсудить эту тему.
zstring_view
В чём предполагаются отличия от std::string_view
?
std::string_view имеет больший размер, так-как он должен содержать либо два указателя, либо указатель и размер. Из-за этого больше накладные расходы при передаче, в аргумента функции и т.п.
Указатель/ссылка на "const std::string" выглядят неплохо, но по сути это "указатель на указатель", что требует двойного разыменования.
std::string_view не гарантирует, что ссылается на строку, оканчивающуюся нулем. Поэтому, принимая откуда-то std::string_view и если эту строку надо далее передать в качестве const char*, это нельзя сделать без выделения/копирования данных, даже, если в 99% случаев принимаемый std::string_view действительно ссылается строку с нулем.
Т.е. полностью перейти на "std::string/std::string_view" и отказаться от "const char*" нельзя. По крайней мере не заплатив за это цену в виде потери производительности. И в коде "const char*" для строк всё равно будет использоваться. Но хочется удобства и единообразия с тем что есть в std. Поэтому хочется иметь обертку над "const char*", класс std::string_view строго такой оберткой не является, у него немного другой смысл.
Поэтому, принимая откуда-то std::string_view и если эту строку надо далее передать в качестве const char*, это нельзя сделать без выделения/копирования данных
Но std::string_ref
здесь не поможет. Данные так или иначе придётся в 1% случаев скопировать (скорее всего на вызывающей стороне; там, что вы назвали «откуда-то»), чтобы получить нуль-терминированную строку, а её можно передать и через std::string_view
. Для гарантии перед распадом в const char*
можно добавить контракт/assert.
Из-за этого больше накладные расходы при передаче, в аргумента функции и т.п.
Можем ли мы количественно оценить величину этих расходов?
Для гарантии перед распадом в const char* можно добавить контракт/assert.
Невозможно без UB проверить, является ли произвольный std::string_view
нуль-терминированным.
Невозможно без UB проверить, является ли произвольный
std::string_view
нуль-терминированным.
Может это как-то в стандарт C добавить, хотя бы и не с блестящей производительностью?
Понятно, что UB идёт от невозможности проверить, выделена ли память под view.data() + view.size()
.
Библиотеки это умеют делать, если есть исходный адрес блока: GLIBC, BSD/OSX, Windows, но если указатель куда-то подвинули с точки, которую вернул malloc
...
Понятно, что UB идёт от невозможности проверить, выделена ли память под view.data() + view.size().
Предлагаю также рассмотреть ситуацию, когда о куче не идёт и речи:
char c = 'a'
std::string_view view(&c, 1);
Большой разницы не вижу. Если память выделена, куча это или стек, то можно "просто" определить, что *(view.data() + view.size())
, вызванный внутри особой библиотечной функции не есть UB (в кавычках, потому что будут разные интересные последствия для оптимизаций, конечно). Проблемы начинаются, если чтение по этой памяти технически невозможно, т. е. делает SIGSERV или вообще лезет в какое-нибудь устройство...
Большой разницы не вижу. Если память выделена, куча это или стек, то можно "просто" определить, что
*(view.data() + view.size())
, вызванный внутри особой библиотечной функции не есть UB (в кавычках, потому что будут разные интересные последствия для оптимизаций, конечно). Проблемы начинаются, если чтение по этой памяти технически невозможно, т. е. делает SIGSERV или вообще лезет в какое-нибудь устройство...
Тогда несколько конструкторов у std::string_view придется выпилить. Интересно, почему сразу так не сделали?
Потому что текущий std::string_view
реализован чисто языковыми конструкциями; то, что я предложил, требует поддержки минимум от libc
и, что более вероятно, ОС, и будет работать небыстро. Но как инструмент для валидации это было бы полезно.
Поэтому давайте вернёмся к обсуждению исходного предложения.
Можем ли мы количественно оценить величину этих расходов?
Я количественно оценить не готов. Но на каждый такой std::string_view нужно два (указателя/целых числа) вместо одного (для string_ref), быстрее закончатся регистры процессора и аргументы функции придется передавать через стек.
Но std::string_ref здесь не поможет. Данные так или иначе придётся в 1% случаев скопировать
Ну вот пусть оно в 1% случаев копирует с вызывающей стороны, чем копирует в 100% случаев в вызываемом коде.
Нашёл прошлое предложение: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1402r0.pdf Результаты голосования: https://github.com/cplusplus/papers/issues/189
нужно два (указателя/целых числа) вместо одного (для string_ref), быстрее закончатся регистры процессора
Обычно как компилятор, так и железо хорошо этот процесс оптимизируют. Поэтому без количественных данных выглядит как premature optimization.
Кстати, в PR1402 предлагалось просто обернуть std::string_view
, не выбрасывая размер.