Telegram Group & Telegram Channel
#madskillz

Нестандартные представления строк

В "стандартном" C++ есть три основных представления для строк. Не будем учитывать "составные" классы (как std::stringstream), у которых нет уникальных концепций.

=====
1️⃣ const char* - просто указатель на начало строки где-то в памяти. Обычно если итерироваться по указателю, то когда-то достигнем нулевой байт \0 (нуль-терминатор), который указывает на конец строки. Все строковые алгоритмы Си завязаны на признак \0 как на конец строки.

=====
2️⃣ std::string - класс строки, владеющий памятью для нее в куче. Запись std::string s = "abcd"; значит, что где-то в куче занята память под байты abcd\0. Известно, std::string гарантированно нуль-терминирован (начиная с C++11).
Маленькие строки полностью помещаются на стек (это называется small string optimization), но пока проигнорируем это.

=====
3️⃣ std::string_view - класс строки, не владеющий памятью. Представляет собой пару const char* s (начало строки) и size_t len (длину строки).
Не обязательно верно то, что *(s + len) == '\0'. 😁 Ведь std::string_view указывает не на всю строку, а только на какую-то ее часть.

=====
Класс std::string поведением похож на контейнер std::vector<char>. Можно посмотреть на какие-нибудь неклассические контейнеры, чтобы создать новые строковые классы, которых нет в стандартном C++.
4️⃣ SmallString - класс строки, владеющий памятью для нее, с поведением как у SmallVector<char>. Реализован в LLVM.
Запись
    std::string s1;
SmallString<256> s2;
Дает два объекта s1 и s2, у которых одинаковый набор методов, но s2 хранится на стеке, если размер строки не превышает 256 символов (планируется, что так будет в 99.9% случаев). Если размер все-таки превысили, то строку начинают хранить в куче.

=====
В бизнес-логике со строками есть проблема. Иногда в коде надо делать много составных строк. Например, для создания строки - "версии" программы нужно сложить несколько строк-частей:

Major + "." + Minor + "." + VersionPatch

В этом случае происходит создание 3 (!) лишних "временных" строк с аллокациями памяти, то есть делается строка Major + ".", потом строка (Major + ".") + Minor и так далее. Более того, итоговая строка (4-я по счету) тоже по сути лишняя, если мы хотели сразу записать итог в какой-нибудь файл, а не хранить результат сложения.

В кодовой базе LLVM есть решение, которое сложно для понимания, но мы его разберем:
5️⃣ Twine - класс "сумма строк". Документация по Twine, но больше информации в исходнике.

Трудности начинаются на уровне названия класса, как у не-носителя английского 😁 Я так и не понял смысл названия.
Вообще, трудности сначала были со словом string. До того, как я начал программировать, у меня это ассоциировалось со стрингами, которые носил Борат. У этого слова куча значений, пусть в нашем случае это будет шнур.
Теперь посмотрим на слово twine. У него тоже вагон значений, пусть в нашем случае это будет бечёвка, пнятненько?
</конец бесполезного абзаца>

Этот класс опасный: он полагается на стремное правило Reference Lifetime Extension, а также на не менее стремное правило, что объекты, созданные для использования в full-expression, не удаляются до конца выполнения этого full-expression (сформулировал как смог).

Функция должна принимать Twine по константной ссылке:
void foo(const Twine& T);
А подавать туда Twine нужно не отходя от кассы, чтобы сработало правило RLE:
foo(Twine(Major) + "." + Minor + "." + VersionPatch);

Благодаря правилу про full-expression, все составные части строки "живы" на стеке, пока не выполнится вызов foo.

Twine внутри себя выглядит как бинарное дерево. У него два "ребенка":
    Child LHS;
Child RHS;
Каждый ребенок это указатель на какой-нибудь строковой объект: const char, или std::string, или std::string_view, или другой Twine ("поддерево"). Также для удобства поддерживаются числа 😁
    union Child
{
const Twine *twine;
const char *cString;
const std::string *stdString;
/* ... */
int decI;
/* ... */
};

ПРОДОЛЖЕНИЕ В ПЕРВОМ КОММЕНТАРИИ (у телеграма ограничение по размеру постов 😟)
Please open Telegram to view this post
VIEW IN TELEGRAM



group-telegram.com/cxx95/97
Create:
Last Update:

#madskillz

Нестандартные представления строк

В "стандартном" C++ есть три основных представления для строк. Не будем учитывать "составные" классы (как std::stringstream), у которых нет уникальных концепций.

=====
1️⃣ const char* - просто указатель на начало строки где-то в памяти. Обычно если итерироваться по указателю, то когда-то достигнем нулевой байт \0 (нуль-терминатор), который указывает на конец строки. Все строковые алгоритмы Си завязаны на признак \0 как на конец строки.

=====
2️⃣ std::string - класс строки, владеющий памятью для нее в куче. Запись std::string s = "abcd"; значит, что где-то в куче занята память под байты abcd\0. Известно, std::string гарантированно нуль-терминирован (начиная с C++11).
Маленькие строки полностью помещаются на стек (это называется small string optimization), но пока проигнорируем это.

=====
3️⃣ std::string_view - класс строки, не владеющий памятью. Представляет собой пару const char* s (начало строки) и size_t len (длину строки).
Не обязательно верно то, что *(s + len) == '\0'. 😁 Ведь std::string_view указывает не на всю строку, а только на какую-то ее часть.

=====
Класс std::string поведением похож на контейнер std::vector<char>. Можно посмотреть на какие-нибудь неклассические контейнеры, чтобы создать новые строковые классы, которых нет в стандартном C++.
4️⃣ SmallString - класс строки, владеющий памятью для нее, с поведением как у SmallVector<char>. Реализован в LLVM.
Запись

    std::string s1;
SmallString<256> s2;
Дает два объекта s1 и s2, у которых одинаковый набор методов, но s2 хранится на стеке, если размер строки не превышает 256 символов (планируется, что так будет в 99.9% случаев). Если размер все-таки превысили, то строку начинают хранить в куче.

=====
В бизнес-логике со строками есть проблема. Иногда в коде надо делать много составных строк. Например, для создания строки - "версии" программы нужно сложить несколько строк-частей:

Major + "." + Minor + "." + VersionPatch

В этом случае происходит создание 3 (!) лишних "временных" строк с аллокациями памяти, то есть делается строка Major + ".", потом строка (Major + ".") + Minor и так далее. Более того, итоговая строка (4-я по счету) тоже по сути лишняя, если мы хотели сразу записать итог в какой-нибудь файл, а не хранить результат сложения.

В кодовой базе LLVM есть решение, которое сложно для понимания, но мы его разберем:
5️⃣ Twine - класс "сумма строк". Документация по Twine, но больше информации в исходнике.

Трудности начинаются на уровне названия класса, как у не-носителя английского 😁 Я так и не понял смысл названия.
Вообще, трудности сначала были со словом string. До того, как я начал программировать, у меня это ассоциировалось со стрингами, которые носил Борат. У этого слова куча значений, пусть в нашем случае это будет шнур.
Теперь посмотрим на слово twine. У него тоже вагон значений, пусть в нашем случае это будет бечёвка, пнятненько?
</конец бесполезного абзаца>

Этот класс опасный: он полагается на стремное правило Reference Lifetime Extension, а также на не менее стремное правило, что объекты, созданные для использования в full-expression, не удаляются до конца выполнения этого full-expression (сформулировал как смог).

Функция должна принимать Twine по константной ссылке:
void foo(const Twine& T);
А подавать туда Twine нужно не отходя от кассы, чтобы сработало правило RLE:
foo(Twine(Major) + "." + Minor + "." + VersionPatch);

Благодаря правилу про full-expression, все составные части строки "живы" на стеке, пока не выполнится вызов foo.

Twine внутри себя выглядит как бинарное дерево. У него два "ребенка":
    Child LHS;
Child RHS;
Каждый ребенок это указатель на какой-нибудь строковой объект: const char, или std::string, или std::string_view, или другой Twine ("поддерево"). Также для удобства поддерживаются числа 😁
    union Child
{
const Twine *twine;
const char *cString;
const std::string *stdString;
/* ... */
int decI;
/* ... */
};

ПРОДОЛЖЕНИЕ В ПЕРВОМ КОММЕНТАРИИ (у телеграма ограничение по размеру постов 😟)

BY C++95


Warning: Undefined variable $i in /var/www/group-telegram/post.php on line 260

Share with your friend now:
group-telegram.com/cxx95/97

View MORE
Open in Telegram


Telegram | DID YOU KNOW?

Date: |

NEWS Pavel Durov, Telegram's CEO, is known as "the Russian Mark Zuckerberg," for co-founding VKontakte, which is Russian for "in touch," a Facebook imitator that became the country's most popular social networking site. Telegram does offer end-to-end encrypted communications through Secret Chats, but this is not the default setting. Standard conversations use the MTProto method, enabling server-client encryption but with them stored on the server for ease-of-access. This makes using Telegram across multiple devices simple, but also means that the regular Telegram chats you’re having with folks are not as secure as you may believe. Andrey, a Russian entrepreneur living in Brazil who, fearing retaliation, asked that NPR not use his last name, said Telegram has become one of the few places Russians can access independent news about the war. The next bit isn’t clear, but Durov reportedly claimed that his resignation, dated March 21st, was an April Fools’ prank. TechCrunch implies that it was a matter of principle, but it’s hard to be clear on the wheres, whos and whys. Similarly, on April 17th, the Moscow Times quoted Durov as saying that he quit the company after being pressured to reveal account details about Ukrainians protesting the then-president Viktor Yanukovych.
from us


Telegram C++95
FROM American