Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

std::string_ref как обертка над const char* #504

Open
kol65536black opened this issue Jan 21, 2022 · 14 comments
Open

std::string_ref как обертка над const char* #504

kol65536black opened this issue Jan 21, 2022 · 14 comments

Comments

@kol65536black
Copy link

kol65536black commented Jan 21, 2022

Хотелось бы иметь обертку над const char* у которой implicit конструктор от const char*, определены операторы сравнения и ряд других полезных функций. Мне кажется странным, но такого нет в библиотеке до сих пор. Может быть есть на то какие-то причины. Хотелось бы обсудить эту тему.

@vtopunov
Copy link

zstring_view

@pavelkryukov
Copy link

В чём предполагаются отличия от std::string_view?

@kol65536black
Copy link
Author

kol65536black commented Jan 23, 2022

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 строго такой оберткой не является, у него немного другой смысл.

@pavelkryukov
Copy link

pavelkryukov commented Jan 23, 2022

Поэтому, принимая откуда-то std::string_view и если эту строку надо далее передать в качестве const char*, это нельзя сделать без выделения/копирования данных

Но std::string_ref здесь не поможет. Данные так или иначе придётся в 1% случаев скопировать (скорее всего на вызывающей стороне; там, что вы назвали «откуда-то»), чтобы получить нуль-терминированную строку, а её можно передать и через std::string_view. Для гарантии перед распадом в const char* можно добавить контракт/assert.

Из-за этого больше накладные расходы при передаче, в аргумента функции и т.п.

Можем ли мы количественно оценить величину этих расходов?

@Smertig
Copy link

Smertig commented Jan 23, 2022

Для гарантии перед распадом в const char* можно добавить контракт/assert.

Невозможно без UB проверить, является ли произвольный std::string_view нуль-терминированным.

@vtopunov
Copy link

Так

@pavelkryukov
Copy link

pavelkryukov commented Jan 23, 2022

Невозможно без UB проверить, является ли произвольный std::string_view нуль-терминированным.

Может это как-то в стандарт C добавить, хотя бы и не с блестящей производительностью?
Понятно, что UB идёт от невозможности проверить, выделена ли память под view.data() + view.size().
Библиотеки это умеют делать, если есть исходный адрес блока: GLIBC, BSD/OSX, Windows, но если указатель куда-то подвинули с точки, которую вернул malloc...

@Smertig
Copy link

Smertig commented Jan 23, 2022

Понятно, что UB идёт от невозможности проверить, выделена ли память под view.data() + view.size().

Предлагаю также рассмотреть ситуацию, когда о куче не идёт и речи:

char c = 'a'
std::string_view view(&c, 1);

@pavelkryukov
Copy link

pavelkryukov commented Jan 23, 2022

Большой разницы не вижу. Если память выделена, куча это или стек, то можно "просто" определить, что *(view.data() + view.size()), вызванный внутри особой библиотечной функции не есть UB (в кавычках, потому что будут разные интересные последствия для оптимизаций, конечно). Проблемы начинаются, если чтение по этой памяти технически невозможно, т. е. делает SIGSERV или вообще лезет в какое-нибудь устройство...

@vtopunov
Copy link

Большой разницы не вижу. Если память выделена, куча это или стек, то можно "просто" определить, что *(view.data() + view.size()), вызванный внутри особой библиотечной функции не есть UB (в кавычках, потому что будут разные интересные последствия для оптимизаций, конечно). Проблемы начинаются, если чтение по этой памяти технически невозможно, т. е. делает SIGSERV или вообще лезет в какое-нибудь устройство...

Тогда несколько конструкторов у std::string_view придется выпилить. Интересно, почему сразу так не сделали?

@pavelkryukov
Copy link

pavelkryukov commented Jan 23, 2022

Потому что текущий std::string_view реализован чисто языковыми конструкциями; то, что я предложил, требует поддержки минимум от libc и, что более вероятно, ОС, и будет работать небыстро. Но как инструмент для валидации это было бы полезно.

Поэтому давайте вернёмся к обсуждению исходного предложения.

@kol65536black
Copy link
Author

Можем ли мы количественно оценить величину этих расходов?

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

@kol65536black
Copy link
Author

kol65536black commented Jan 24, 2022

Но std::string_ref здесь не поможет. Данные так или иначе придётся в 1% случаев скопировать

Ну вот пусть оно в 1% случаев копирует с вызывающей стороны, чем копирует в 100% случаев в вызываемом коде.

@pavelkryukov
Copy link

Нашёл прошлое предложение: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1402r0.pdf
Результаты голосования: cplusplus/papers#189

нужно два (указателя/целых числа) вместо одного (для string_ref), быстрее закончатся регистры процессора

Обычно как компилятор, так и железо хорошо этот процесс оптимизируют. Поэтому без количественных данных выглядит как premature optimization.
Кстати, в PR1402 предлагалось просто обернуть std::string_view, не выбрасывая размер.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants