Pull to refresh

Comments 21

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

Шёл 2023 год, а в статьях GCC 6.3. Не удивительно при оригинале статьи из 2017 года. При этом ни про устройство, ни про гарантии и потенциальный UB от повисших указателей. `string_view` - замечательная вещь, но хоть какие-нибудь размышления и сравнения с char* не помешали бы.

Ну и воспользуюсь случаем и порекламмирую panda::string. CopyOnWrite(CoW), все те же substr тоже без копирований и аллокаций, но с полной гарантией безопасности. Тот же SSO на 23 байта. Цена полной безопасности дешёвого subbstr - CoW не лучшим образом дружит с потоками. Но если не шарить стейт и передавать копии данных аккуратно, ну или как мы вообще не использовать потоки, то это совсем не цена.

Просто любопытно, sizeof(panda::string) vs sizeof(std::string) - одинаковые или нет?

Сложно утвержать сразу про все реализации std, но скорее нет, чем да. На 64-битной архитектуре sizeof(panda::string) == 40. Стандартная у меня 32 (Debian 11, GCC 10.2). То есть просто так передавать по значению тоже может быть чуть-чуть дороговато, лучше бы по ссылке. Но скопировать себе для хранения - ни о чём на фоне аллокации и копии в std.

Запрещено. В силу требований потоковой безопасности в первую очередь. Вот только не всем она нужна, особенно с учётом её цены. Такой же пример - std::shared_ptr, его атомарный счётчик слишком уж дорог для многих применений. Имхо, это нарушение базового принципа "не платить за то, что не используешь". Поэтому мы отказались от этих довольно слабых гарантий (класс в целом всё равно не thread-safe) в пользу производительности в одном потоке.

P.S. Струкутуру проекта поправили, ссылка изменилась panda::string

вот интересно, автор проводит какие то исследования производительности и не пишет в какой конфигурации он этот тестовый пример компилировал в Release или в Debug. И если это Release то с какими ключами оптимизации?

Может я отстал от жизни и эти настройки какие-то стандартные что ли теперь? Или эти настройки теперь (для новых стандартов С++) не влияют на производительность?

Может кто-то пояснить?

Из своего опыта я помню что в Release компилятор не то что вызовы к переопределенной функции может выкинуть, он может и целые переменные проигнорировать в коде.

Назовите три причины почему надо передавать std::string_view в функции по значению? :)

Там в тексте есть такой пассаж:

In the byvalue case, the string_view is passed in the register pair (%rdi, %rsi), so returning its “size” member is just a register-to-register move.

Стал искать, что это за регистровая пара %rdi, %rsi ? В других процессорах бывает, что два регистра объединяются в регистровую пару, представляя как бы один регистр в два раза большего размера. Если действительно в x86 существует регистровая пара из 64-х битных rdi и rsi, то эта пара должна иметь размер 128 бит.

Но команда movq %rsi, %rax перебрасывает значение из 64-битного rsi в 64-х битный rax. При чем тут регистровая пара?

Кроме того, я нигде не нашел информации что rdi и rsi способны объединяться в пару. Да, у них есть связь, потому что rsi - это регистр-источник (source), а rdi - это регистр-приемник (destination), и, видимо они индексные (i) потому что используются в командах типа repe movsb. Но это же не регистровая пара.

В общем, автор меня запутал. Что он хотел сказать?

Имеется в виду System V AMD64 ABI calling convention. В нём первые два аргумента передаются через регистры rdi и rsi. Но в примере возвращается только размер строки, т.ч. используется только один регистр. Типичная проблема "писарей" доходчиво излагать свои мысли.

  1. Блин, неужели было сложно поставить номера строчек в примерах кода?

  2. Давно не писал на С++, но там все такой же древний, архаичный вывод сообщений в std::cout, как этот?

std::cout << "std::string_view::substr: " << durStringView.count() << " seconds" << std::endl;

Нормального, удобного форматирования до сих пор нет?

Ага, f-строк, как в Питоне, по-прежнему нет... Жаль.

Вообще, стандартному С++ давно не хватает строкового пула. Как в Lua. Всё настолько сурово, что я уже всерьез хочу прикрутить рантайм Luajit к С/С++ проекту просто ради ссылочной системы на иммутабельные строки.

Так если есть список строковых литералов, то оно и так оптимизировалось и складировалось в .rodata. Или речь про динамически считываемые строки которые потом не меняются?

std::string совершенно плевать на строковые литералы в чистом виде

  1. сравнение строк все равно через memcmp идет

  2. std::string в поле класса все равно хранит копию данных

  3. строка может прийти из внешнего документа (json, например) Суть строкового пула, что память на "ещё одну" строку выделяться не будет (кроме ссылки). А когда 95% времени выполнения процесса занимает malloc() - это становится существенно

Ближайшее, я так понимаю, boost::pool. А так согласен, с иммутабельными вещами в плюсах довольно плохо, но если очень хочется, то можете написать некоторый пропозал в стандарт.

GCC 6.3.0.

Тем временем поддержка std::string_view появилась только в GCC 7. Возникает вопрос каким макаром все эти тесты проводились? На черновых версиях реализации?

ух ты!

оказывается, что если вместо данных хранить указатель на них, то копирование будет работать быстрее!

Sign up to leave a comment.