Notice: file_put_contents(): Write of 17065 bytes failed with errno=28 No space left on device in /var/www/tgoop/post.php on line 50

Warning: file_put_contents(): Only 8192 of 25257 bytes written, possibly out of free disk space in /var/www/tgoop/post.php on line 50
C++95@cxx95 P.97
CXX95 Telegram 97
#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
👍13🔥6🙏1🖕1



tgoop.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


Share with your friend now:
tgoop.com/cxx95/97

View MORE
Open in Telegram


Telegram News

Date: |

Telegram iOS app: In the “Chats” tab, click the new message icon in the right upper corner. Select “New Channel.” Don’t publish new content at nighttime. Since not all users disable notifications for the night, you risk inadvertently disturbing them. Telegram desktop app: In the upper left corner, click the Menu icon (the one with three lines). Select “New Channel” from the drop-down menu. End-to-end encryption is an important feature in messaging, as it's the first step in protecting users from surveillance. Done! Now you’re the proud owner of a Telegram channel. The next step is to set up and customize your channel.
from us


Telegram C++95
FROM American