<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dw="https://www.dreamwidth.org">
  <id>tag:dreamwidth.org,2016-12-25:2601916</id>
  <title>Пятнадцать байтов на стек от конца</title>
  <subtitle>Serge Vakulenko</subtitle>
  <author>
    <name>Serge Vakulenko</name>
  </author>
  <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/"/>
  <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom"/>
  <updated>2026-04-29T07:57:23Z</updated>
  <dw:journal username="vak" type="personal"/>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1536966</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1536966.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1536966"/>
    <title>ASCII аквариум на Rust</title>
    <published>2026-04-29T07:57:23Z</published>
    <updated>2026-04-29T07:57:23Z</updated>
    <category term="rust"/>
    <category term="компьютерные игры"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">Для полноты впечатлений я переписал аквариум и на Rust. Заодно будет красивый пример приложения TUI с помощью пакета &lt;a href="https://crates.io/crates/crossterm"&gt;crossterm&lt;/a&gt;. Это один из аналогов &lt;a href="https://en.wikipedia.org/wiki/Curses_(programming_library)"&gt;curses&lt;/a&gt; в мире Rust.&lt;br /&gt;&lt;br /&gt;Исходники: &lt;a href="https://github.com/sergev/rustyquarium"&gt;sergev/rustyquarium&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1536966" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1524683</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1524683.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1524683"/>
    <title>Браузер в терминале</title>
    <published>2026-03-26T08:29:12Z</published>
    <updated>2026-03-26T08:29:57Z</updated>
    <category term="программистское"/>
    <category term="rust"/>
    <dw:security>public</dw:security>
    <dw:reply-count>12</dw:reply-count>
    <content type="html">Один крутой чувак сделал браузер, работающий в терминале из командной строки. Даже запускается через SSH если нужно. Поддерживаются практически все современные фичи, включая WebGL, WebGPU, воспроизведение аудио и видео, анимация и прочее. Работает быстро, запускается за секунду, даёт 60 кадров в секунду и не кушает процессор в режиме ожидания. &lt;br /&gt;&lt;br /&gt;Проект на гитхабе: &lt;a href="https://github.com/fathyb/carbonyl"&gt;fathyb/carbonyl&lt;/a&gt;. Можно скачать бинарники для Линукса и мака, или собрать из текстов.&lt;br /&gt;&lt;br /&gt;Пример: &lt;br /&gt;&lt;a href="https://vak.dreamwidth.org/file/2010524.jpg"&gt;&lt;img src="https://vak.dreamwidth.org/file/800x800/2010524.jpg" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1524683" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1424395</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1424395.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1424395"/>
    <title>И опять простой текстовый редактор на Rust</title>
    <published>2025-07-28T22:05:35Z</published>
    <updated>2025-07-28T22:05:35Z</updated>
    <category term="программистское"/>
    <category term="rust"/>
    <dw:security>public</dw:security>
    <dw:reply-count>9</dw:reply-count>
    <content type="html">Пишем текстовый редактор с нуля, пошаговая инструкция из 7 частей: &lt;a href="https://medium.com/@otukof/build-your-text-editor-with-rust-678a463f968b"&gt;настройка&lt;/a&gt;, &lt;a href="https://medium.com/@otukof/build-your-text-editor-with-rust-part-2-74e03daef237"&gt;считывание нажатий клавиш и вход в &amp;laquo;сырой режим&amp;raquo;&lt;/a&gt;, &lt;a href="https://medium.com/@otukof/build-your-text-editor-with-rust-part-3-b030670fa815"&gt;рисование на экране и перемещение курсора&lt;/a&gt;, &lt;a href="https://medium.com/@otukof/build-your-text-editor-with-rust-part-4-fd4a8b8641f8"&gt;отображение текстовых файлов&lt;/a&gt;, &lt;a href="https://medium.com/@otukof/build-your-text-editor-with-rust-part-5-e363c16f542b"&gt;редактирование текстовых файлов и сохранение изменений&lt;/a&gt;, &lt;a href="https://medium.com/@otukof/build-your-text-editor-with-rust-part-6-3cff61dc2de5"&gt;реализация поиска&lt;/a&gt;, &lt;a href="https://medium.com/@otukof/build-your-text-editor-with-rust-final-part-4c841a649900"&gt;добавление подсветки синтаксиса&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Результат: &lt;a href="https://github.com/Kofituo/pound"&gt;github.com/Kofituo/pound&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1424395" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1406516</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1406516.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1406516"/>
    <title>Asterinas</title>
    <published>2025-06-15T21:14:11Z</published>
    <updated>2025-06-15T21:16:29Z</updated>
    <category term="программистское"/>
    <category term="rust"/>
    <dw:security>public</dw:security>
    <dw:reply-count>2</dw:reply-count>
    <content type="html">Народ наваял линукс-совместимую операционку на чистом Rust. &lt;br /&gt;&lt;br /&gt;&amp;quot;&lt;a href="https://arxiv.org/html/2506.03876v1"&gt;Asterinas: A Linux ABI-Compatible, Rust-Based Framekernel OS with a Small and Sound TCB&lt;/a&gt;&amp;quot;&lt;br /&gt;&lt;br /&gt;Исходники на гитхабе: &lt;a href="https://github.com/asterinas/asterinas"&gt;asterinas/asterinas&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;&lt;a href="https://arxiv.org/html/2506.03876v1"&gt;&lt;img src="https://arxiv.org/html/2506.03876v1/x4.png" width="640" height="385" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1406516" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1404523</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1404523.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1404523"/>
    <title>Quine–McCluskey algorithm</title>
    <published>2025-06-10T23:37:20Z</published>
    <updated>2025-06-10T23:37:20Z</updated>
    <category term="программистское"/>
    <category term="python"/>
    <category term="rust"/>
    <dw:security>public</dw:security>
    <dw:reply-count>14</dw:reply-count>
    <content type="html">На днях обсуждали со &lt;span style='white-space: nowrap;'&gt;&lt;a href='https://spamsink.dreamwidth.org/profile'&gt;&lt;img src='https://www.dreamwidth.org/img/silk/identity/user.png' alt='[personal profile] ' width='17' height='17' style='vertical-align: text-bottom; border: 0; padding-right: 1px;' /&gt;&lt;/a&gt;&lt;a href='https://spamsink.dreamwidth.org/'&gt;&lt;b&gt;spamsink&lt;/b&gt;&lt;/a&gt;&lt;/span&gt; минимизацию булевских функций. Тема из далёкого студенчества. Задачка нетривиальная, но давно и глубоко проработанная. Озадачил нею Грока, получил два решения:&lt;br /&gt;&lt;br /&gt;на Питоне: &lt;a href="https://github.com/sergev/vak-opensource/blob/master/languages/python/minimize-boolean-function.py"&gt;minimize-boolean-function.py&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;на Rust: &lt;a href="https://github.com/sergev/vak-opensource/blob/master/languages/rust/minimize-boolean-function.rs"&gt;minimize-boolean-function.rs&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Функция с 8 переменными вычисляется на Rust за шесть секунд:&lt;blockquote&gt;&lt;pre&gt;
$ rustc minimize-boolean-function.rs&lt;br /&gt;&lt;br /&gt;$ /usr/bin/time ./minimize-boolean-function &lt;br /&gt;&lt;br /&gt;Truth table: 0000000000X10000000000000000000000000000000000000000000000000000010X010X010X010X010X010X010X010X010X010X010X010X010X010X010X010X00000000001X0000000000000000000000000000000000001X1X1X1X1X1X1X1X0000000000000000000000000000000000000000000000000000000000000000&lt;br /&gt;8-variable result: ~ABH + ~B~C~DE~FG + A~BCD&lt;br /&gt;        6.26 real         6.22 user         0.03 sys&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1404523" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1393485</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1393485.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1393485"/>
    <title>edit.com переписали на Rust</title>
    <published>2025-05-19T21:16:49Z</published>
    <updated>2025-05-19T23:45:21Z</updated>
    <category term="rust"/>
    <category term="программистское"/>
    <dw:security>public</dw:security>
    <dw:reply-count>5</dw:reply-count>
    <content type="html">Микрософт выложил в открытый доступ &lt;a href="https://github.com/microsoft/edit/"&gt;исходники текстового редактора edit&lt;/a&gt;. Свободная опенсорсная лицензия MIT. Реализация на языке Rust наследует не букву, но дух древнего редактора &lt;a href="https://en.wikipedia.org/wiki/MS-DOS_Editor"&gt;edit.com&lt;/a&gt; из MS-DOS 5.0. Работает под Линуксом и Windows. На маке скомпилировать мне пока не удалось.&lt;br /&gt;&lt;br /&gt;Было тридцать пять лет назад:&lt;br /&gt;&lt;br /&gt;&lt;a href="https://vak.dreamwidth.org/file/1675746.jpg"&gt;&lt;img src="https://vak.dreamwidth.org/file/480x480/1675746.jpg" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Стало: &lt;br /&gt;&lt;br /&gt;&lt;a href="https://vak.dreamwidth.org/file/1675812.jpg"&gt;&lt;img src="https://vak.dreamwidth.org/file/480x480/1675812.jpg" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1393485" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1370588</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1370588.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1370588"/>
    <title>Ungrammar</title>
    <published>2025-04-01T22:02:05Z</published>
    <updated>2025-04-02T01:43:44Z</updated>
    <category term="программистское"/>
    <category term="искусственный интеллект"/>
    <category term="rust"/>
    <dw:security>public</dw:security>
    <dw:reply-count>8</dw:reply-count>
    <content type="html">Почему бы не подурачиться 1 апреля. Думаю, парсер грамматики Си вполне сойдёт за дурацкую затею. Тем более я ж не сам напрягаться собираюсь, а ИИ подряжу. Я упоминал про ASDL, а есть ещё &lt;a href="https://rust-analyzer.github.io/blog/2020/10/24/introducing-ungrammar.html" style=""&gt;Ungrammar&lt;/a&gt;, другой способ описывать синтаксические деревья. Я попросил Грок сбацать мне грамматику языка Си. Он предложил упрощённый вариант:&lt;blockquote&gt;&lt;pre&gt;
// Top-level program structure&lt;br /&gt;TranslationUnit = Declaration*&lt;br /&gt;&lt;br /&gt;// Declarations&lt;br /&gt;Declaration = Type Identifier ';'&lt;br /&gt;            | Type Identifier '(' ParameterList ')' CompoundStmt&lt;br /&gt;ParameterList = (Type Identifier (',' Type Identifier)*)?&lt;br /&gt;&lt;br /&gt;// Types&lt;br /&gt;Type = 'int'&lt;br /&gt;     | 'float'&lt;br /&gt;     | 'char'&lt;br /&gt;     | 'void'&lt;br /&gt;&lt;br /&gt;// Statements&lt;br /&gt;Stmt = CompoundStmt&lt;br /&gt;     | ExprStmt&lt;br /&gt;     | IfStmt&lt;br /&gt;     | WhileStmt&lt;br /&gt;     | ReturnStmt&lt;br /&gt;&lt;br /&gt;CompoundStmt = '{' Declaration* Stmt* '}'&lt;br /&gt;ExprStmt = Expr ';'&lt;br /&gt;IfStmt = 'if' '(' Expr ')' Stmt ('else' Stmt)?&lt;br /&gt;WhileStmt = 'while' '(' Expr ')' Stmt&lt;br /&gt;ReturnStmt = 'return' Expr? ';'&lt;br /&gt;&lt;br /&gt;// Expressions&lt;br /&gt;Expr = AssignmentExpr&lt;br /&gt;AssignmentExpr = EqualityExpr ('=' EqualityExpr)?&lt;br /&gt;EqualityExpr = RelationalExpr (('==' | '!=') RelationalExpr)?&lt;br /&gt;RelationalExpr = AddExpr (('&amp;lt;' | '&amp;gt;' | '&amp;lt;=' | '&amp;gt;=') AddExpr)?&lt;br /&gt;AddExpr = MultExpr (('+' | '-') MultExpr)*&lt;br /&gt;MultExpr = UnaryExpr (('*' | '/') UnaryExpr)*&lt;br /&gt;UnaryExpr = PrimaryExpr&lt;br /&gt;          | '-' UnaryExpr&lt;br /&gt;          | '!' UnaryExpr&lt;br /&gt;PrimaryExpr = Identifier&lt;br /&gt;            | Number&lt;br /&gt;            | String&lt;br /&gt;            | '(' Expr ')'&lt;br /&gt;&lt;br /&gt;// Basic tokens&lt;br /&gt;Identifier = &amp;lt;token&amp;gt;&lt;br /&gt;Number = &amp;lt;token&amp;gt;&lt;br /&gt;String = &amp;lt;token&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;Неплохо, вполне годится. А теперь говорю, напиши парсер этой грамматики на Rust. С третьей попытки получился работающий код: &lt;a href="https://github.com/sergev/vak-opensource/blob/master/languages/rust/c_parser/src/main.rs"&gt;c_parser/src/main.rs&lt;/a&gt;. Полтыщи строк нетривиального кода одним махом побиваши.&lt;br /&gt;&lt;br /&gt;В качестве теста обработаем Си-шную программу:&lt;blockquote&gt;&lt;pre&gt;
int x = 42;&lt;br /&gt;int main(int argc) {&lt;br /&gt;    int y = 3 + 5 * 2;&lt;br /&gt;    if (y &amp;gt; x) {&lt;br /&gt;        return 1;&lt;br /&gt;    } else {&lt;br /&gt;        return 0;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/blockquote&gt;Компилируем, запускаем:&lt;blockquote&gt;&lt;pre&gt;
$ cargo run
...&lt;br /&gt;     Running `/home/vak/c_parser/target/debug/c_parser`&lt;br /&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://vak.dreamwidth.org/1370588.html#cutid1"&gt;результат&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/blockquote&gt;Остаётся добавить указатели, массивы, структуры, тайпдефы и прочие фичи, и язык Си у нас в кармане. 😀&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1370588" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1369729</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1369729.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1369729"/>
    <title>Спецификация языка Rust</title>
    <published>2025-03-31T01:20:44Z</published>
    <updated>2025-03-31T01:25:13Z</updated>
    <category term="rust"/>
    <dw:security>public</dw:security>
    <dw:reply-count>1</dw:reply-count>
    <content type="html">Наконец появилось вменяемое описание языка.&lt;a href="https://spec.ferrocene.dev/index.html"&gt;&lt;br /&gt;&lt;br /&gt;spec.ferrocene.dev&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Этот документ ещё не стал официальным, но со временем станет. &lt;a href="https://rustfoundation.org/media/ferrous-systems-donates-ferrocene-language-specification-to-rust-project/"&gt;Подробности здесь&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1369729" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1369390</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1369390.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1369390"/>
    <title>Компиляторостроителям</title>
    <published>2025-03-31T01:00:52Z</published>
    <updated>2025-03-31T01:06:39Z</updated>
    <category term="программистское"/>
    <category term="c++"/>
    <category term="rust"/>
    <dw:security>public</dw:security>
    <dw:reply-count>6</dw:reply-count>
    <content type="html">Грамматика стандарта Си-2011:&lt;ul&gt;&lt;li&gt;&lt;a href="https://www.quut.com/c/ANSI-C-grammar-l-2011.html"&gt;Лексический сканер Lex&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://www.quut.com/c/ANSI-C-grammar-y-2011.html"&gt;Грамматический парсер Yacc&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Полезные статьи:&lt;ul&gt;&lt;li&gt;&lt;a href="https://pub.sergev.org/doc/asdl97.pdf"&gt;The Zephyr Abstract Syntax Description Language&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://pub.sergev.org/doc/Jones-ImplementingASTs.pdf"&gt;Abstract Syntax Tree Implementation Idioms&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Пара Си компиляторов, написанных на языке Rust по &lt;a href="https://vak.dreamwidth.org/1369172.html"&gt;упомянутой книжке&lt;/a&gt;:&lt;ul&gt;&lt;li&gt;&lt;a href="https://github.com/jyn514/saltwater"&gt;jyn514/saltwater&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/ClementTsang/rustcc"&gt;ClementTsang/rustcc&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1369390" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1362693</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1362693.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1362693"/>
    <title>Сегодня 3/14</title>
    <published>2025-03-14T21:25:45Z</published>
    <updated>2025-03-14T21:25:45Z</updated>
    <category term="rust"/>
    <dw:security>public</dw:security>
    <dw:reply-count>5</dw:reply-count>
    <content type="html">Красивая реализация вычисления пи на Rust.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/elkasztano/piday25"&gt;https://github.com/elkasztano/piday25&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1362693" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1358043</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1358043.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1358043"/>
    <title>Тип Cow&amp;lt;T&amp;gt; - клонирование при записи</title>
    <published>2025-03-03T04:57:39Z</published>
    <updated>2025-03-03T05:04:34Z</updated>
    <category term="программистское"/>
    <category term="rust"/>
    <category term="c++"/>
    <dw:security>public</dw:security>
    <dw:reply-count>7</dw:reply-count>
    <content type="html">Концепция copy-on-write не представлена в традиционных языках программирования, поэтому вызывает трудности у народа. Тип Cow&amp;lt;T&amp;gt; в Rust часто используется со строками, чтобы избежать лишнего клонирования. Грок покажет нам упрощённую реализацию.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;em&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;Question:&lt;/span&gt;&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;&lt;span style="color: rgb(51, 153, 102);"&gt; Please show a possible implementation of Rust's type std::borrow::Cow in C++.&lt;/span&gt;&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;I'll show you how to implement a simplified version of Rust's std::borrow::Cow (Copy-on-Write) in C++. Rust's Cow is an enum that can hold either a borrowed reference (&amp;amp;'a T) or an owned value (T), typically used to avoid unnecessary cloning. In C++, we can approximate this using a combination of templates, variants, and smart pointers.&lt;br /&gt;&lt;br /&gt;Here's a possible implementation: &lt;a href="https://github.com/sergev/vak-opensource/blob/master/languages/c%2B%2B/cow.cpp"&gt;cow.cpp&lt;/a&gt;.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;
#include &amp;lt;variant&amp;gt;&lt;br /&gt;#include &amp;lt;memory&amp;gt;&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;br /&gt;#include &amp;lt;stdexcept&amp;gt;&lt;br /&gt;&lt;br /&gt;// A simplified Cow implementation in C++&lt;br /&gt;template&amp;lt;typename T&amp;gt;&lt;br /&gt;class Cow {&lt;br /&gt;private:&lt;br /&gt;    // Using variant to hold either a borrowed pointer or an owned value&lt;br /&gt;    std::variant&amp;lt;const T*, std::unique_ptr&amp;lt;T&amp;gt;&amp;gt; data;&lt;br /&gt;&lt;br /&gt;public:&lt;br /&gt;    // Constructor for borrowed value&lt;br /&gt;    explicit Cow(const T* borrowed) : data(borrowed) {&lt;br /&gt;        if (!borrowed) {&lt;br /&gt;            throw std::invalid_argument(&amp;quot;Borrowed pointer cannot be null&amp;quot;);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Constructor for owned value&lt;br /&gt;    explicit Cow(T&amp;amp;&amp;amp; owned) : data(std::make_unique&amp;lt;T&amp;gt;(std::move(owned))) {}&lt;br /&gt;&lt;br /&gt;    // Copy constructor&lt;br /&gt;    Cow(const Cow&amp;amp; other) {&lt;br /&gt;        if (std::holds_alternative&amp;lt;const T*&amp;gt;(other.data)) {&lt;br /&gt;            data = std::get&amp;lt;const T*&amp;gt;(other.data);&lt;br /&gt;        } else {&lt;br /&gt;            const auto&amp;amp; owned = std::get&amp;lt;std::unique_ptr&amp;lt;T&amp;gt;&amp;gt;(other.data);&lt;br /&gt;            data = std::make_unique&amp;lt;T&amp;gt;(*owned);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Move constructor&lt;br /&gt;    Cow(Cow&amp;amp;&amp;amp; other) noexcept = default;&lt;br /&gt;&lt;br /&gt;    // Assignment operators&lt;br /&gt;    Cow&amp;amp; operator=(const Cow&amp;amp; other) {&lt;br /&gt;        if (this != &amp;amp;other) {&lt;br /&gt;            Cow temp(other);&lt;br /&gt;            swap(*this, temp);&lt;br /&gt;        }&lt;br /&gt;        return *this;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    Cow&amp;amp; operator=(Cow&amp;amp;&amp;amp; other) noexcept = default;&lt;br /&gt;&lt;br /&gt;    // Access the underlying value (non-mutating)&lt;br /&gt;    const T&amp;amp; operator*() const {&lt;br /&gt;        if (std::holds_alternative&amp;lt;const T*&amp;gt;(data)) {&lt;br /&gt;            return *std::get&amp;lt;const T*&amp;gt;(data);&lt;br /&gt;        }&lt;br /&gt;        return *std::get&amp;lt;std::unique_ptr&amp;lt;T&amp;gt;&amp;gt;(data);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    const T* operator-&amp;gt;() const {&lt;br /&gt;        return &amp;amp;(**this);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Check if the Cow holds a borrowed value&lt;br /&gt;    bool is_borrowed() const {&lt;br /&gt;        return std::holds_alternative&amp;lt;const T*&amp;gt;(data);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Check if the Cow holds an owned value&lt;br /&gt;    bool is_owned() const {&lt;br /&gt;        return std::holds_alternative&amp;lt;std::unique_ptr&amp;lt;T&amp;gt;&amp;gt;(data);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Convert to owned value if borrowed (clone on write)&lt;br /&gt;    void to_owned() {&lt;br /&gt;        if (is_borrowed()) {&lt;br /&gt;            data = std::make_unique&amp;lt;T&amp;gt;(*std::get&amp;lt;const T*&amp;gt;(data));&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Swap implementation&lt;br /&gt;    friend void swap(Cow&amp;amp; lhs, Cow&amp;amp; rhs) noexcept {&lt;br /&gt;        using std::swap;&lt;br /&gt;        swap(lhs.data, rhs.data);&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://vak.dreamwidth.org/1358043.html#cutid1"&gt;объяснения и пример&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1358043" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1357765</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1357765.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1357765"/>
    <title>Тип RwLock&amp;lt;T&amp;gt;</title>
    <published>2025-03-03T04:19:20Z</published>
    <updated>2025-03-03T04:36:15Z</updated>
    <category term="программистское"/>
    <category term="c++"/>
    <category term="rust"/>
    <dw:security>public</dw:security>
    <dw:reply-count>1</dw:reply-count>
    <content type="html">Тип &lt;a href="https://vak.dreamwidth.org/1357536.html"&gt;Mutex&amp;lt;T&amp;gt;&lt;/a&gt; хорош, но разрешает доступ нескольким потокам только по очереди. Что если нам чаще требуется только читать объект, а изменять только изредка? Через RwLock&amp;lt;T&amp;gt; можно получить множественный доступ на чтение.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;&lt;em&gt;Question:&lt;/em&gt;&lt;/span&gt;&lt;/strong&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;&lt;em&gt; Please show a meaningful C++ implementation of type RwLock&amp;lt;T&amp;gt;.&lt;/em&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I'll create a C++ implementation of RwLock&amp;lt;T&amp;gt; similar to Rust's RwLock, which provides a reader-writer lock allowing multiple readers or one writer. We'll use C++'s std::shared_mutex (available since C++17) as the underlying synchronization primitive.&lt;br /&gt;&lt;br /&gt;Here's the implementation: &lt;a href="https://github.com/sergev/vak-opensource/blob/master/languages/c%2B%2B/rwlock.cpp"&gt;rwlock.cpp&lt;/a&gt;.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;
#include &amp;lt;shared_mutex&amp;gt;&lt;br /&gt;#include &amp;lt;memory&amp;gt;&lt;br /&gt;&lt;br /&gt;template&amp;lt;typename T&amp;gt;&lt;br /&gt;class RwLock {&lt;br /&gt;private:&lt;br /&gt;    T data;&lt;br /&gt;    mutable &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;strong&gt;std::shared_mutex&lt;/strong&gt;&lt;/span&gt; mtx;  // mutable to allow locking in const methods&lt;br /&gt;&lt;br /&gt;public:&lt;br /&gt;    // Constructor&lt;br /&gt;    explicit RwLock(T value) : data(std::move(value)) {}&lt;br /&gt;&lt;br /&gt;    // Read guard class (multiple readers allowed)&lt;br /&gt;    class ReadGuard {&lt;br /&gt;    private:&lt;br /&gt;        const T&amp;amp; data_ref;&lt;br /&gt;        &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;strong&gt;std::shared_lock&lt;/strong&gt;&lt;/span&gt;&amp;lt;std::shared_mutex&amp;gt; lock;&lt;br /&gt;&lt;br /&gt;    public:&lt;br /&gt;        ReadGuard(const T&amp;amp; d, std::shared_mutex&amp;amp; m)&lt;br /&gt;            : data_ref(d), lock(m) {}&lt;br /&gt;&lt;br /&gt;        const T&amp;amp; operator*() const { return data_ref; }&lt;br /&gt;        const T* operator-&amp;gt;() const { return &amp;amp;data_ref; }&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    // Write guard class (exclusive writer)&lt;br /&gt;    class WriteGuard {&lt;br /&gt;    private:&lt;br /&gt;        T&amp;amp; data_ref;&lt;br /&gt;        &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;strong&gt;std::unique_lock&lt;/strong&gt;&lt;/span&gt;&amp;lt;std::shared_mutex&amp;gt; lock;&lt;br /&gt;&lt;br /&gt;    public:&lt;br /&gt;        WriteGuard(T&amp;amp; d, std::shared_mutex&amp;amp; m)&lt;br /&gt;            : data_ref(d), lock(m) {}&lt;br /&gt;&lt;br /&gt;        T&amp;amp; operator*() { return data_ref; }&lt;br /&gt;        T* operator-&amp;gt;() { return &amp;amp;data_ref; }&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    // Lock methods&lt;br /&gt;    ReadGuard read_lock() const {&lt;br /&gt;        return ReadGuard(data, mtx);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    WriteGuard write_lock() {&lt;br /&gt;        return WriteGuard(data, mtx);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Prevent copying&lt;br /&gt;    RwLock(const RwLock&amp;amp;) = delete;&lt;br /&gt;    RwLock&amp;amp; operator=(const RwLock&amp;amp;) = delete;&lt;br /&gt;&lt;br /&gt;    // Allow move construction&lt;br /&gt;    RwLock(RwLock&amp;amp;&amp;amp;) = default;&lt;br /&gt;    RwLock&amp;amp; operator=(RwLock&amp;amp;&amp;amp;) = default;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://vak.dreamwidth.org/1357765.html#cutid1"&gt;объяснения&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1357765" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1357536</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1357536.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1357536"/>
    <title>Что такое Mutex&amp;lt;T&amp;gt;</title>
    <published>2025-03-03T03:43:50Z</published>
    <updated>2025-03-03T04:12:37Z</updated>
    <category term="программистское"/>
    <category term="rust"/>
    <category term="c++"/>
    <dw:security>public</dw:security>
    <dw:reply-count>1</dw:reply-count>
    <content type="html">Продолжаем изучать примитивы языка Rust. В этом деле Грок неплохой помощник. Как выясняется, тип Mutex&amp;lt;T&amp;gt; представляет собой удобную комбинацию классов std::mutex и std::unique_lock из Си++.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;&lt;em&gt;Question:&lt;/em&gt;&lt;/span&gt;&lt;/strong&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;&lt;em&gt; Please show me a possible implementation of type Mutex&amp;lt;T&amp;gt; in C++.&lt;/em&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I'll provide an implementation of a Mutex&amp;lt;T&amp;gt; type in C++ that mimics Rust's Mutex. Rust's Mutex provides mutual exclusion with a lock guard pattern, so we'll create a similar construct in C++ using the standard library's threading primitives.&lt;br /&gt;&lt;br /&gt;Here's a possible implementation: &lt;a href="https://github.com/sergev/vak-opensource/blob/master/languages/c%2B%2B/mutex.cpp"&gt;mutex.cpp&lt;/a&gt;.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;
#include &amp;lt;mutex&amp;gt;&lt;br /&gt;#include &amp;lt;memory&amp;gt;&lt;br /&gt;&lt;br /&gt;template&amp;lt;typename T&amp;gt;&lt;br /&gt;class Mutex {&lt;br /&gt;private:&lt;br /&gt;    T data;&lt;br /&gt;    &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;strong&gt;std::mutex&lt;/strong&gt;&lt;/span&gt; mtx;&lt;br /&gt;&lt;br /&gt;public:&lt;br /&gt;    // Constructor&lt;br /&gt;    explicit Mutex(T value) : data(std::move(value)) {}&lt;br /&gt;&lt;br /&gt;    // Lock guard class (similar to Rust's MutexGuard)&lt;br /&gt;    class LockGuard {&lt;br /&gt;    private:&lt;br /&gt;        T&amp;amp; data_ref;&lt;br /&gt;        &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;strong&gt;std::unique_lock&lt;/strong&gt;&lt;/span&gt;&amp;lt;std::mutex&amp;gt; lock;&lt;br /&gt;&lt;br /&gt;    public:&lt;br /&gt;        LockGuard(T&amp;amp; d, std::mutex&amp;amp; m)&lt;br /&gt;            : data_ref(d), lock(m) {}&lt;br /&gt;&lt;br /&gt;        // Access the underlying data&lt;br /&gt;        T&amp;amp; operator*() { return data_ref; }&lt;br /&gt;        T* operator-&amp;gt;() { return &amp;amp;data_ref; }&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    // Lock method that returns the guard&lt;br /&gt;    LockGuard lock() {&lt;br /&gt;        return LockGuard(data, mtx);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Prevent copying&lt;br /&gt;    Mutex(const Mutex&amp;amp;) = delete;&lt;br /&gt;    Mutex&amp;amp; operator=(const Mutex&amp;amp;) = delete;&lt;br /&gt;&lt;br /&gt;    // Allow move construction&lt;br /&gt;    Mutex(Mutex&amp;amp;&amp;amp;) = default;&lt;br /&gt;    Mutex&amp;amp; operator=(Mutex&amp;amp;&amp;amp;) = default;&lt;br /&gt;};&lt;/pre&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://vak.dreamwidth.org/1357536.html#cutid1"&gt;объяснения и пример&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1357536" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1357090</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1357090.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1357090"/>
    <title>Тип Option&amp;lt;T&amp;gt; в языке Rust</title>
    <published>2025-03-02T01:17:31Z</published>
    <updated>2025-03-03T03:52:06Z</updated>
    <category term="rust"/>
    <category term="c++"/>
    <category term="программистское"/>
    <dw:security>public</dw:security>
    <dw:reply-count>5</dw:reply-count>
    <content type="html">Устав от &lt;a href="https://vak.dreamwidth.org/1353337.html"&gt;сложных концепций&lt;/a&gt;, глянем что-нибудь простое, скажем тип Option&amp;lt;T&amp;gt;. Это контейнер на одно значение произвольного типа, которое может отсутствовать. В Си++17 появился практически идентичный класс &lt;a href="https://en.cppreference.com/w/cpp/utility/optional"&gt;std::optional&lt;/a&gt;. Но мы попросим Грок состряпать нам решение, максимально близкое к Rust.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;&lt;em&gt;Question:&lt;/em&gt;&lt;/span&gt;&lt;/strong&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;&lt;em&gt; Please implement type Option in C++, making it as close to Rust as possible, but still convenient for C++.&lt;/em&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Let's create a C++ implementation of Rust's Option type. In Rust, Option is an enum that represents either Some(value) or None, used for handling cases where a value might be absent. Here's a C++ version that mimics this behavior while adapting to C++ idioms:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;
#include &amp;lt;utility&amp;gt;&lt;br /&gt;#include &amp;lt;stdexcept&amp;gt;&lt;br /&gt;&lt;br /&gt;template &amp;lt;typename T&amp;gt;&lt;br /&gt;class Option {&lt;br /&gt;private:&lt;br /&gt;    bool has_value;&lt;br /&gt;    union {&lt;br /&gt;        T value;&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;public:&lt;br /&gt;    // Constructors&lt;br /&gt;    Option() : has_value(false) {}&lt;br /&gt;&lt;br /&gt;    explicit Option(const T&amp;amp; val) : has_value(true), value(val) {}&lt;br /&gt;&lt;br /&gt;    explicit Option(T&amp;amp;&amp;amp; val) : has_value(true), value(std::move(val)) {}&lt;br /&gt;&lt;br /&gt;    // Copy constructor&lt;br /&gt;    Option(const Option&amp;amp; other) : has_value(other.has_value) {&lt;br /&gt;        if (has_value) {&lt;br /&gt;            new(&amp;amp;value) T(other.value);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Move constructor&lt;br /&gt;    Option(Option&amp;amp;&amp;amp; other) noexcept : has_value(other.has_value) {&lt;br /&gt;        if (has_value) {&lt;br /&gt;            new(&amp;amp;value) T(std::move(other.value));&lt;br /&gt;            other.has_value = false;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Destructor&lt;br /&gt;    ~Option() {&lt;br /&gt;        if (has_value) {&lt;br /&gt;            value.~T();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Assignment operators&lt;br /&gt;    Option&amp;amp; operator=(const Option&amp;amp; other) {&lt;br /&gt;        if (this != &amp;amp;other) {&lt;br /&gt;            if (has_value) {&lt;br /&gt;                value.~T();&lt;br /&gt;            }&lt;br /&gt;            has_value = other.has_value;&lt;br /&gt;            if (has_value) {&lt;br /&gt;                new(&amp;amp;value) T(other.value);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        return *this;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    Option&amp;amp; operator=(Option&amp;amp;&amp;amp; other) noexcept {&lt;br /&gt;        if (this != &amp;amp;other) {&lt;br /&gt;            if (has_value) {&lt;br /&gt;                value.~T();&lt;br /&gt;            }&lt;br /&gt;            has_value = other.has_value;&lt;br /&gt;            if (has_value) {&lt;br /&gt;                new(&amp;amp;value) T(std::move(other.value));&lt;br /&gt;                other.has_value = false;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        return *this;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Static methods to create Some and None&lt;br /&gt;    static Option Some(const T&amp;amp; val) { return Option(val); }&lt;br /&gt;    static Option None() { return Option(); }&lt;br /&gt;&lt;br /&gt;    // Check if contains value&lt;br /&gt;    bool is_some() const { return has_value; }&lt;br /&gt;    bool is_none() const { return !has_value; }&lt;br /&gt;&lt;br /&gt;    // Access value (unsafe - throws if None)&lt;br /&gt;    T&amp;amp; unwrap() {&lt;br /&gt;        if (!has_value) {&lt;br /&gt;            throw std::runtime_error(&amp;quot;Called unwrap on None&amp;quot;);&lt;br /&gt;        }&lt;br /&gt;        return value;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    const T&amp;amp; unwrap() const {&lt;br /&gt;        if (!has_value) {&lt;br /&gt;            throw std::runtime_error(&amp;quot;Called unwrap on None&amp;quot;);&lt;br /&gt;        }&lt;br /&gt;        return value;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Access with default value&lt;br /&gt;    T unwrap_or(const T&amp;amp; default_value) const {&lt;br /&gt;        return has_value ? value : default_value;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Get value or compute default&lt;br /&gt;    template &amp;lt;typename F&amp;gt;&lt;br /&gt;    T unwrap_or_else(F&amp;amp;&amp;amp; func) const {&lt;br /&gt;        return has_value ? value : func();&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;// Helper function to make creation more convenient&lt;br /&gt;template &amp;lt;typename T&amp;gt;&lt;br /&gt;Option&amp;lt;T&amp;gt; some(const T&amp;amp; value) {&lt;br /&gt;    return Option&amp;lt;T&amp;gt;::Some(value);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;template &amp;lt;typename T&amp;gt;&lt;br /&gt;Option&amp;lt;T&amp;gt; none() {&lt;br /&gt;    return Option&amp;lt;T&amp;gt;::None();&lt;br /&gt;}&lt;/pre&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://vak.dreamwidth.org/1357090.html#cutid1"&gt;объяснения и пример&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1357090" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1356804</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1356804.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1356804"/>
    <title>Тип RefCell&amp;lt;T&amp;gt;</title>
    <published>2025-03-02T00:34:56Z</published>
    <updated>2025-03-02T01:23:17Z</updated>
    <category term="c++"/>
    <category term="rust"/>
    <category term="программистское"/>
    <dw:security>public</dw:security>
    <dw:reply-count>5</dw:reply-count>
    <content type="html">Тип RefCell&amp;lt;T&amp;gt;, аналогично &lt;a href="https://vak.dreamwidth.org/1356398.html"&gt;Cell&amp;lt;T&amp;gt;&lt;/a&gt;, тоже контейнер на одно значение произвольного типа. Но к самому значению нельзя достучаться прямо, а надо сначала получить ссылку на него методами borrow() или borrow_mut(). &lt;br /&gt;&lt;br /&gt;Метод borrow() даёт &lt;em&gt;&lt;strong&gt;константную ссылку&lt;/strong&gt;&lt;/em&gt;. Значение можно получить методом get(), но нельзя изменить. Таких константных ссылок можно насоздавать сколько угодно - при условии, что не существует мутабельной ссылки.&lt;br /&gt;&lt;br /&gt;Метод borrow_mut() даёт &lt;em&gt;&lt;strong&gt;мутабельную ссылку&lt;/strong&gt;&lt;/em&gt;. Значение можно изменить методом set(). Но мутабельную ссылку можно получить только одну-единственную, и при отсутствии константных ссылок.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;em&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;Question:&lt;/span&gt;&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;&lt;span style="color: rgb(51, 153, 102);"&gt; Please show me implementation of type RefCell&amp;lt;T&amp;gt; in C++.&lt;/span&gt;&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Let&amp;rsquo;s tackle implementing Rust&amp;rsquo;s RefCell&amp;lt;T&amp;gt; in C++. This is an exciting challenge because RefCell&amp;lt;T&amp;gt; takes interior mutability a step further than Cell&amp;lt;T&amp;gt;. While Cell&amp;lt;T&amp;gt; allows mutation through a shared reference with a simple copy or swap, RefCell&amp;lt;T&amp;gt; provides borrowed access&amp;mdash;either immutable (shared) or mutable (exclusive)&amp;mdash;with runtime checks to enforce Rust&amp;rsquo;s borrowing rules: you can have many immutable borrows or one mutable borrow, but never both at once. In Rust, this is all about safety without locks, and we&amp;rsquo;ll aim to replicate that dynamic enforcement in C++.&lt;br /&gt;&lt;br /&gt;In C++, we don&amp;rsquo;t have a borrow checker, so we&amp;rsquo;ll use a runtime mechanism to track borrows, similar to how RefCell uses a counter in Rust. The implementation will involve:&lt;br /&gt; &lt;ul&gt;&lt;li&gt;A container for the value.&lt;/li&gt;&lt;li&gt;Counters for active immutable and mutable borrows.&lt;/li&gt;&lt;li&gt;Methods to borrow the value immutably (borrow) or mutably (borrow_mut), returning smart pointers that enforce the borrowing rules.&lt;/li&gt;&lt;li&gt;Runtime checks to panic (or throw, in C++ terms) if the rules are violated.&lt;/li&gt;&lt;/ul&gt;Here&amp;rsquo;s the implementation: &lt;a href="https://github.com/sergev/vak-opensource/blob/master/languages/c%2B%2B/refcell.cpp"&gt;refcell.cpp&lt;/a&gt;.&lt;blockquote&gt;&lt;pre&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;memory&amp;gt;&lt;br /&gt;#include &amp;lt;stdexcept&amp;gt;&lt;br /&gt;#include &amp;lt;utility&amp;gt;&lt;br /&gt;&lt;br /&gt;template &amp;lt;typename T&amp;gt;&lt;br /&gt;class RefCell {&lt;br /&gt;private:&lt;br /&gt;    T value;&lt;br /&gt;    mutable size_t borrow_count;  // Tracks immutable borrows&lt;br /&gt;    mutable bool borrowed_mut;    // Tracks if there's a mutable borrow&lt;br /&gt;&lt;br /&gt;public:&lt;br /&gt;    explicit RefCell(T initial) : value(std::move(initial)), borrow_count(0), borrowed_mut(false) {}&lt;br /&gt;&lt;br /&gt;    class Ref {&lt;br /&gt;    private:&lt;br /&gt;        const RefCell&amp;lt;T&amp;gt;* cell;&lt;br /&gt;        friend class RefCell&amp;lt;T&amp;gt;;&lt;br /&gt;&lt;br /&gt;        Ref(const RefCell&amp;lt;T&amp;gt;* c) : cell(c) {&lt;br /&gt;            if (cell-&amp;gt;borrowed_mut) {&lt;br /&gt;                throw std::runtime_error(&amp;quot;Already mutably borrowed&amp;quot;);&lt;br /&gt;            }&lt;br /&gt;            cell-&amp;gt;borrow_count++;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    public:&lt;br /&gt;        ~Ref() {&lt;br /&gt;            if (cell) {&lt;br /&gt;                cell-&amp;gt;borrow_count--;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        Ref(const Ref&amp;amp;) = delete;&lt;br /&gt;        Ref&amp;amp; operator=(const Ref&amp;amp;) = delete;&lt;br /&gt;        Ref(Ref&amp;amp;&amp;amp; other) noexcept : cell(other.cell) { other.cell = nullptr; }&lt;br /&gt;&lt;br /&gt;        const T&amp;amp; &lt;span style="color: rgb(0, 0, 255);"&gt;get()&lt;/span&gt; const { return cell-&amp;gt;value; }&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    class RefMut {&lt;br /&gt;    private:&lt;br /&gt;        RefCell&amp;lt;T&amp;gt;* cell;&lt;br /&gt;        friend class RefCell&amp;lt;T&amp;gt;;&lt;br /&gt;&lt;br /&gt;        RefMut(RefCell&amp;lt;T&amp;gt;* c) : cell(c) {&lt;br /&gt;            if (c-&amp;gt;borrow_count &amp;gt; 0 || c-&amp;gt;borrowed_mut) {&lt;br /&gt;                throw std::runtime_error(&amp;quot;Already borrowed&amp;quot;);&lt;br /&gt;            }&lt;br /&gt;            c-&amp;gt;borrowed_mut = true;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;    public:&lt;br /&gt;        ~RefMut() {&lt;br /&gt;            if (cell) {&lt;br /&gt;                cell-&amp;gt;borrowed_mut = false;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        RefMut(const RefMut&amp;amp;) = delete;&lt;br /&gt;        RefMut&amp;amp; operator=(const RefMut&amp;amp;) = delete;&lt;br /&gt;        RefMut(RefMut&amp;amp;&amp;amp; other) noexcept : cell(other.cell) { other.cell = nullptr; }&lt;br /&gt;&lt;br /&gt;        T&amp;amp; &lt;span style="color: rgb(0, 0, 255);"&gt;&lt;strong&gt;get()&lt;/strong&gt;&lt;/span&gt; { return cell-&amp;gt;value; }&lt;br /&gt;&lt;br /&gt;        void &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;strong&gt;set&lt;/strong&gt;&lt;/span&gt;(T new_value) {&lt;br /&gt;            cell-&amp;gt;value = std::move(new_value);&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    Ref &lt;strong&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;borrow()&lt;/span&gt;&lt;/strong&gt; const { return Ref(this); }&lt;br /&gt;    RefMut &lt;strong&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;borrow_mut()&lt;/span&gt;&lt;/strong&gt; { return RefMut(this); }&lt;br /&gt;};&lt;/pre&gt;&lt;/blockquote&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://vak.dreamwidth.org/1356804.html#cutid1"&gt;объяснения&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1356804" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1356398</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1356398.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1356398"/>
    <title>Тип Cell&amp;lt;T&amp;gt;</title>
    <published>2025-03-01T21:58:19Z</published>
    <updated>2025-03-02T01:38:44Z</updated>
    <category term="c++"/>
    <category term="rust"/>
    <category term="программистское"/>
    <dw:security>public</dw:security>
    <dw:reply-count>4</dw:reply-count>
    <content type="html">Продолжаю двигаться по &lt;a href="https://vak.dreamwidth.org/1353337.html"&gt;списку&lt;/a&gt;: изучаю базовые примитивы языка Rust. Сегодня рассмотрим Cell&amp;lt;T&amp;gt;, &lt;a href="https://vak.dreamwidth.org/1356804.html"&gt;RefCell&amp;lt;T&amp;gt;&lt;/a&gt; и, на десерт, &lt;a href="https://vak.dreamwidth.org/1357090.html"&gt;Option&amp;lt;T&amp;gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Cell это простой контейнер на одно значение произвольного типа. С одной хитрой фичей: если значение неизменяемое (то есть имеет атрибут const), Cell позволяет обходить это ограничение и всё-таки &lt;em&gt;&lt;strong&gt;изменять&lt;/strong&gt;&lt;/em&gt; его. Аналогично ключевому слову &amp;quot;mutable&amp;quot; в Си++. Спросим у grok.com.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;&lt;em&gt;Question:&lt;/em&gt;&lt;/span&gt;&lt;/strong&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;&lt;em&gt; Please show me how type Cell&amp;lt;T&amp;gt; can be implemented in C++.&lt;/em&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Let&amp;rsquo;s dive into how we might implement Rust&amp;rsquo;s Cell&amp;lt;T&amp;gt; in C++. Rust&amp;rsquo;s Cell&amp;lt;T&amp;gt; is a fascinating type - it provides interior mutability, allowing you to mutate its contents even when you only have a shared reference, all while being safe in a single-threaded context. It&amp;rsquo;s lightweight, with no runtime overhead beyond the mutation itself, and it doesn&amp;rsquo;t involve locks since it&amp;rsquo;s not thread-safe (that&amp;rsquo;s what RefCell or atomics are for in Rust). In C++, we don&amp;rsquo;t have the exact same ownership and borrowing rules, so we&amp;rsquo;ll need to adapt the concept while preserving its spirit.&lt;br /&gt;&lt;br /&gt;The core idea of Cell&amp;lt;T&amp;gt; is simple: it wraps a value of type T and provides methods to get and set that value, bypassing C++&amp;rsquo;s usual const-correctness restrictions in a controlled way. Rust uses it to allow mutation through shared references, so in C++, we&amp;rsquo;ll aim for something that lets us modify a value even when we might otherwise be constrained, like through a const reference, while keeping the implementation straightforward.&lt;br /&gt;&lt;br /&gt;Here&amp;rsquo;s a basic implementation in C++: &lt;a href="https://github.com/sergev/vak-opensource/blob/master/languages/c%2B%2B/cell.cpp"&gt;cell.cpp&lt;/a&gt;.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;
#include &amp;lt;utility&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;template &amp;lt;typename T&amp;gt;&lt;br /&gt;class Cell {&lt;br /&gt;private:&lt;br /&gt;    &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;strong&gt;mutable&lt;/strong&gt;&lt;/span&gt; T value; // Mutable to allow mutation even when Cell is const&lt;br /&gt;&lt;br /&gt;public:&lt;br /&gt;    // Constructor&lt;br /&gt;    explicit Cell(T initial) : value(std::move(initial)) {}&lt;br /&gt;&lt;br /&gt;    // Get a copy of the value&lt;br /&gt;    T get() const {&lt;br /&gt;        return value;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Set a new value&lt;br /&gt;    void set(T new_value) const {&lt;br /&gt;        value = std::move(new_value);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Replace the value and return the old one&lt;br /&gt;    T replace(T new_value) const {&lt;br /&gt;        T old_value = std::move(value);&lt;br /&gt;        value = std::move(new_value);&lt;br /&gt;        return old_value;&lt;br /&gt;    }&lt;br /&gt;};&lt;/pre&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://vak.dreamwidth.org/1356398.html#cutid1"&gt;объяснения и пример&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1356398" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1356026</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1356026.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1356026"/>
    <title>Что такое тип Weak для Arc</title>
    <published>2025-02-28T20:56:27Z</published>
    <updated>2025-02-28T21:01:14Z</updated>
    <category term="rust"/>
    <category term="c++"/>
    <category term="программистское"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">Реализация слабого указателя Weak для Arc отличается от &lt;a href="https://vak.dreamwidth.org/1355587.html"&gt;Weak для Rc&lt;/a&gt;. Суть та же, но для работы в многопоточной среде используются атомарные счётчики и инкременты-декременты.&lt;br /&gt;&lt;br /&gt;Смысл слабого указателя в том, что он не мешает удалить объект. От указателя Arc&lt;t&gt; можно вызвать метод create_weak(), и он вернёт &amp;quot;слабый&amp;quot; указатель типа Weak&lt;t&gt; на тот же объект. Со слабым указателем мало что можно делать, кроме как вызовом метода upgrade() снова получить сильный указатель. Или не получить - если объект уже к этому времени пропал.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;em&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;Question:&lt;/span&gt;&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;&lt;span style="color: rgb(51, 153, 102);"&gt; Weak for Rc was good. Now please do the same for Weak for Arc. Please show me how it could look in C++.&lt;/span&gt;&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Let&amp;rsquo;s implement a version of Rust&amp;rsquo;s Weak for Arc (Atomic Reference Counting) in C++. In Rust, Arc is similar to Rc but is thread-safe, using atomic operations for reference counting. This allows Arc to be shared across threads, and its companion Weak provides a non-owning reference that can be upgraded to an Arc if the data still exists. The key difference from Rc is that Arc uses atomic counters (std::sync::atomic::AtomicUsize in Rust) instead of plain integers, ensuring safe concurrent access.&lt;br /&gt;&lt;br /&gt;In C++, we&amp;rsquo;ll use std::atomic&amp;lt;size_t&amp;gt; for the counters to mimic this thread-safety. The structure will be similar to our Rc and Weak implementation, but we&amp;rsquo;ll adjust the reference counting to be atomic. Here&amp;rsquo;s how it could look: &lt;a href="https://github.com/sergev/vak-opensource/blob/master/languages/c%2B%2B/weak-rc.cpp"&gt;weak-arc.cpp&lt;/a&gt;.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://vak.dreamwidth.org/1356026.html#cutid1"&gt;исходный код на Си++&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;h3&gt;Key Differences from Rc/Weak&lt;/h3&gt;1. Atomic Counters:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;ArcControlBlock uses std::atomic&amp;lt;size_t&amp;gt; for strong_count and weak_count.&lt;/li&gt;&lt;li&gt;Operations like fetch_add, fetch_sub, and compare_exchange_weak ensure thread-safe updates.&lt;/li&gt;&lt;/ul&gt;2. Memory Ordering:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;std::memory_order_relaxed is used for non-critical reads/writes where ordering isn&amp;rsquo;t needed.&lt;/li&gt;&lt;li&gt;std::memory_order_acq_rel (acquire-release) is used for decrements and upgrades to ensure proper synchronization:&lt;ul&gt;&lt;li&gt;Acquire ensures we see all prior writes when reading the count.&lt;/li&gt;&lt;li&gt;Release ensures our writes are visible before the count drops.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;upgrade() uses compare_exchange_weak to atomically increment the strong count only if it&amp;rsquo;s still non-zero, preventing race conditions.&lt;/li&gt;&lt;/ul&gt;3. Thread-Safety:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The reference counting is safe across threads, but accessing *data isn&amp;rsquo;t inherently thread-safe. In a real application, you&amp;rsquo;d need to synchronize data access (e.g., with a mutex) if T is modified concurrently.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Notes&lt;/h3&gt;Comparison to std::shared_ptr: C++&amp;rsquo;s std::shared_ptr with std::weak_ptr is similar but uses a control block with atomic counters internally. Our version makes this explicit for clarity.&lt;br /&gt;&lt;br /&gt;This implementation captures the essence of Weak for Arc in a thread-safe way.&lt;/t&gt;&lt;/t&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1356026" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1355587</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1355587.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1355587"/>
    <title>Исследуем тип Weak для Rc</title>
    <published>2025-02-28T20:21:13Z</published>
    <updated>2025-02-28T20:44:18Z</updated>
    <category term="rust"/>
    <category term="c++"/>
    <category term="программистское"/>
    <dw:security>public</dw:security>
    <dw:reply-count>5</dw:reply-count>
    <content type="html">Продолжим разбираться с &lt;a href="https://vak.dreamwidth.org/1353337.html"&gt;умными указателями&lt;/a&gt; в Rust. Вчера я показывал &lt;a href="https://vak.dreamwidth.org/1354705.html"&gt;Rc&lt;/a&gt;&lt;t&gt; и &lt;a href="https://vak.dreamwidth.org/1354856.html"&gt;Arc&lt;/a&gt;&lt;t&gt;. Они похожи на &lt;a href="https://en.cppreference.com/w/cpp/memory/shared_ptr"&gt;shared_ptr&lt;/a&gt;. Теперь глянем типы Weak для них. Начнём с Weak для Rc.&lt;br /&gt;&lt;br /&gt;Фишка указателя Weak в том, что он не мешает удалить объект. От указателя Rc&amp;lt;T&amp;gt; можно вызвать метод create_weak(), и он вернёт &amp;quot;слабый&amp;quot; указатель типа Weak&amp;lt;T&amp;gt; на тот же объект. Со слабым указателем мало что можно делать, кроме как вызовом метода upgrade() снова получить сильный указатель. Или не получить - если объект уже к этому времени пропал.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;em&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;Question:&lt;/span&gt;&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;&lt;span style="color: rgb(51, 153, 102);"&gt; Let's talk about Weak for Rc for now. Please show me how it can be implemented in C++.&lt;/span&gt;&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Let&amp;rsquo;s dive into implementing a Weak pointer analogous to Rust&amp;rsquo;s Weak for Rc in C++. In Rust, Rc (Reference Counting) provides shared ownership of data, and Weak is a non-owning reference that prevents reference cycles and allows access to the data only if it still exists (i.e., if the strong reference count hasn&amp;rsquo;t dropped to zero). We&amp;rsquo;ll replicate this behavior in C++ using a combination of smart pointers and manual reference counting.&lt;br /&gt;&lt;br /&gt;In C++, the closest equivalent to Rc is std::shared_ptr, which manages a strong reference count. For Weak, we&amp;rsquo;ll mimic Rust&amp;rsquo;s Weak by using std::weak_ptr, which is designed to work with std::shared_ptr and provides a non-owning reference. However, to make this a clear learning exercise and align it closely with Rust&amp;rsquo;s semantics, I&amp;rsquo;ll first show a simplified manual implementation before tying it to the standard library.&lt;br /&gt;&lt;h3&gt;Manual Implementation Concept&lt;/h3&gt;Rust&amp;rsquo;s Rc and Weak rely on two counters:&lt;br /&gt; &lt;ul&gt;&lt;li&gt;Strong count: Number of owning Rc references.&lt;/li&gt;&lt;li&gt;Weak count: Number of non-owning Weak references.&lt;/li&gt;&lt;/ul&gt;The data is deallocated when the strong count reaches zero, and the control block (holding the counters) is deallocated when both strong and weak counts reach zero. Let&amp;rsquo;s implement this in C++.&lt;br /&gt;&lt;h3&gt;C++ Implementation&lt;/h3&gt;Here&amp;rsquo;s a basic implementation &lt;a href="https://github.com/sergev/vak-opensource/blob/master/languages/c%2B%2B/weak-rc.cpp"&gt;weak-rc.cpp&lt;/a&gt;:&lt;blockquote&gt;&lt;pre&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://vak.dreamwidth.org/1355587.html#cutid1"&gt;исходный код на Си++&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;h3&gt;Explanation&lt;/h3&gt;1. RcControlBlock: Manages the strong and weak reference counts.&lt;br /&gt;2. Rc&amp;lt;T&amp;gt;:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Owns the data and increments the strong count on copy.&lt;/li&gt;&lt;li&gt;Deletes the data when the strong count hits zero.&lt;/li&gt;&lt;li&gt;Provides a method to create a Weak pointer.&lt;/li&gt;&lt;/ul&gt;3. Weak&amp;lt;T&amp;gt;:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Non-owning reference; increments the weak count on creation.&lt;/li&gt;&lt;li&gt;Provides upgrade(), which returns an Rc if the strong count is greater than zero, or std::nullopt if the data is gone.&lt;/li&gt;&lt;li&gt;Cleans up the control block when both counts reach zero.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Key Differences&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Rust&amp;rsquo;s Weak returns an Option&amp;lt;Rc&amp;lt;T&amp;gt;&amp;gt; on upgrade(), while std::weak_ptr::lock() returns a std::shared_ptr or null.&lt;/li&gt;&lt;li&gt;The manual C++ version uses std::optional to mimic Rust&amp;rsquo;s Option.&lt;/li&gt;&lt;li&gt;Rust enforces thread-safety with Arc separately, while std::shared_ptr is not thread-safe for modification without synchronization (akin to Rc).&lt;/li&gt;&lt;/ul&gt;&lt;/t&gt;&lt;/t&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1355587" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1354856</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1354856.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1354856"/>
    <title>Что такое Arc&amp;lt;T&amp;gt;</title>
    <published>2025-02-27T23:59:23Z</published>
    <updated>2025-02-28T08:20:56Z</updated>
    <category term="программистское"/>
    <category term="c++"/>
    <category term="rust"/>
    <dw:security>public</dw:security>
    <dw:reply-count>9</dw:reply-count>
    <content type="html">Давайте выясним, чем тип Arc&amp;lt;T&amp;gt; отличается от &lt;a href="https://vak.dreamwidth.org/1354705.html"&gt;Rc&amp;lt;T&amp;gt;&lt;/a&gt;. Название означает Atomically Reference Counted. Как объясняет нам grok.com, эта штука почти эквивалентна std::shared_ptr из Си++20 и позже. Сгенерённый исходник смотрите в файле: &lt;a href="https://github.com/sergev/vak-opensource/blob/master/languages/c%2B%2B/arc.cpp"&gt;arc.cpp&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;&lt;em&gt;Question:&lt;/em&gt;&lt;/span&gt;&lt;/strong&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;&lt;em&gt; How Arc&amp;lt;T&amp;gt; would look if implemented in C++?&lt;/em&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Let&amp;rsquo;s dive into how we might implement something like Rust&amp;rsquo;s Arc&amp;lt;T&amp;gt; in C++. For those unfamiliar, Arc&amp;lt;T&amp;gt; in Rust is a thread-safe, reference-counted smart pointer that allows multiple owners of some data, incrementing a counter when cloned and decrementing it when dropped, freeing the data when the count hits zero. It&amp;rsquo;s built for concurrent use, so it uses atomic operations to manage the count safely across threads. We&amp;rsquo;ll aim to replicate that behavior in C++.&lt;br /&gt;&lt;br /&gt;In C++, we don&amp;rsquo;t have a direct equivalent in the standard library, but std::shared_ptr comes close. However, std::shared_ptr isn&amp;rsquo;t guaranteed to use atomic reference counting for the control block in all implementations (pre-C++20, at least), and its atomic operations were only standardized with std::atomic&amp;lt;std::shared_ptr&amp;gt; in C++20. To truly mirror Arc&amp;lt;T&amp;gt;, we&amp;rsquo;ll roll our own simplified version using atomic counters, focusing on thread-safety and the core mechanics.&lt;br /&gt;&lt;br /&gt;Here&amp;rsquo;s how it could look:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;
#include &amp;lt;atomic&amp;gt;&lt;br /&gt;#include &amp;lt;memory&amp;gt;&lt;br /&gt;#include &amp;lt;utility&amp;gt;&lt;br /&gt;#include &amp;lt;type_traits&amp;gt;&lt;br /&gt;&lt;br /&gt;// Define Inner as a standalone template struct&lt;br /&gt;template &amp;lt;typename T&amp;gt;&lt;br /&gt;struct ArcInner {&lt;br /&gt;    T data;&lt;br /&gt;    &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;strong&gt;std::atomic&lt;/strong&gt;&lt;/span&gt;&amp;lt;int&amp;gt; ref_count;&lt;br /&gt;&lt;br /&gt;    template &amp;lt;typename... Args&amp;gt;&lt;br /&gt;    ArcInner(Args&amp;amp;&amp;amp;... args) : data(std::forward&amp;lt;Args&amp;gt;(args)...), ref_count(1) {}&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;template &amp;lt;typename T&amp;gt;&lt;br /&gt;class Arc {&lt;br /&gt;private:&lt;br /&gt;    ArcInner&amp;lt;T&amp;gt;* ptr;&lt;br /&gt;&lt;br /&gt;    void increment_count() {&lt;br /&gt;        if (ptr) {&lt;br /&gt;            ptr-&amp;gt;ref_count.fetch_add(1, std::memory_order_relaxed);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    void decrement_count() {&lt;br /&gt;        if (ptr) {&lt;br /&gt;            if (ptr-&amp;gt;ref_count.fetch_sub(1, std::memory_order_acq_rel) == 1) {&lt;br /&gt;                delete ptr;&lt;br /&gt;                ptr = nullptr;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;public:&lt;br /&gt;    // Constructor with constraint: Args must be convertible to T&lt;br /&gt;    template &amp;lt;typename... Args, typename = std::enable_if_t&amp;lt;std::is_constructible_v&amp;lt;T, Args...&amp;gt;&amp;gt;&amp;gt;&lt;br /&gt;    explicit Arc(Args&amp;amp;&amp;amp;... args) : ptr(new ArcInner&amp;lt;T&amp;gt;(std::forward&amp;lt;Args&amp;gt;(args)...)) {}&lt;br /&gt;&lt;br /&gt;    // Copy constructor&lt;br /&gt;    Arc(const Arc&amp;amp; other) : ptr(other.ptr) {&lt;br /&gt;        increment_count();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Move constructor&lt;br /&gt;    Arc(Arc&amp;amp;&amp;amp; other) noexcept : ptr(other.ptr) {&lt;br /&gt;        other.ptr = nullptr;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Assignment operators&lt;br /&gt;    Arc&amp;amp; operator=(const Arc&amp;amp; other) {&lt;br /&gt;        if (this != &amp;amp;other) {&lt;br /&gt;            decrement_count();&lt;br /&gt;            ptr = other.ptr;&lt;br /&gt;            increment_count();&lt;br /&gt;        }&lt;br /&gt;        return *this;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    Arc&amp;amp; operator=(Arc&amp;amp;&amp;amp; other) noexcept {&lt;br /&gt;        if (this != &amp;amp;other) {&lt;br /&gt;            decrement_count();&lt;br /&gt;            ptr = other.ptr;&lt;br /&gt;            other.ptr = nullptr;&lt;br /&gt;        }&lt;br /&gt;        return *this;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Destructor&lt;br /&gt;    ~Arc() {&lt;br /&gt;        decrement_count();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Dereference operators&lt;br /&gt;    T&amp;amp; operator*() const { return ptr-&amp;gt;data; }&lt;br /&gt;    T* operator-&amp;gt;() const { return &amp;amp;ptr-&amp;gt;data; }&lt;br /&gt;&lt;br /&gt;    // Get the reference count&lt;br /&gt;    int use_count() const { return ptr ? ptr-&amp;gt;ref_count.load(std::memory_order_relaxed) : 0; }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;// Helper function to create an Arc&lt;br /&gt;template &amp;lt;typename T, typename... Args&amp;gt;&lt;br /&gt;Arc&amp;lt;T&amp;gt; make_arc(Args&amp;amp;&amp;amp;... args) {&lt;br /&gt;    return Arc&amp;lt;T&amp;gt;(std::forward&amp;lt;Args&amp;gt;(args)...);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://vak.dreamwidth.org/1354856.html#cutid1"&gt;объяснения и пример&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1354856" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1354705</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1354705.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1354705"/>
    <title>Что такое Rc&amp;lt;T&amp;gt;</title>
    <published>2025-02-27T23:17:48Z</published>
    <updated>2025-02-27T23:35:49Z</updated>
    <category term="программистское"/>
    <category term="rust"/>
    <category term="c++"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">Продолжим разбираться с &lt;a href="https://vak.dreamwidth.org/1353337.html"&gt;умными указателями&lt;/a&gt; в Rust. Глянем на тип Rc&amp;lt;T&amp;gt;. Название расшифровывается как Reference Counted, что намекает. Спросим grok.com. Выходит почти тот же shared_ptr, с двумя отличиями: он не может оказаться NULL, и счетчик простой, а не std::atomic. Сгенерённый ним исходник смотрите в файле: &lt;a href="https://github.com/sergev/vak-opensource/blob/master/languages/c%2B%2B/rc.cpp"&gt;rc.cpp&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;&lt;em&gt;Question:&lt;/em&gt;&lt;/span&gt;&lt;/strong&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;&lt;em&gt; How Rc&amp;lt;T&amp;gt; would look if implemented in C++?&lt;/em&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Let&amp;rsquo;s re-implement Rust&amp;rsquo;s Rc&amp;lt;T&amp;gt; in C++ - a fascinating exercise since Rc&amp;lt;T&amp;gt; introduces reference-counted shared ownership, contrasting with the unique ownership of Box&amp;lt;T&amp;gt;. In Rust, Rc&amp;lt;T&amp;gt; (short for &amp;quot;Reference Counted&amp;quot;) allows multiple owners of a heap-allocated T, tracking the number of references via a counter. When the last Rc is dropped, the T is deallocated. This is akin to C++&amp;rsquo;s std::shared_ptr&amp;lt;T&amp;gt;, but we&amp;rsquo;ll craft a custom version to mirror Rust&amp;rsquo;s Rc&amp;lt;T&amp;gt; behavior, focusing on its single-threaded nature (unlike Arc&amp;lt;T&amp;gt; for multi-threading).&lt;br /&gt;&lt;h3&gt;What Rc&amp;lt;T&amp;gt; Does in Rust&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Allocation: Places a T on the heap with a reference count.&lt;/li&gt;&lt;li&gt;Shared Ownership: Multiple Rc&amp;lt;T&amp;gt; instances can point to the same T, incrementing the count.&lt;/li&gt;&lt;li&gt;Cloning: Rc::clone creates a new reference, bumping the count.&lt;/li&gt;&lt;li&gt;Deallocation: When the last Rc is dropped (count hits 0), T is destroyed and memory freed.&lt;/li&gt;&lt;li&gt;No Mutability: Rc&amp;lt;T&amp;gt; alone doesn&amp;rsquo;t allow mutation (use RefCell&amp;lt;T&amp;gt; or Cell&amp;lt;T&amp;gt; for that).&lt;/li&gt;&lt;li&gt;Non-Atomic: Single-threaded, unlike Arc&amp;lt;T&amp;gt;.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;C++ Implementation&lt;/h3&gt;We&amp;rsquo;ll create an Rc&amp;lt;T&amp;gt; class in C++ that:&lt;br /&gt; &lt;ul&gt;&lt;li&gt;Uses a control block to store the reference count and T together.&lt;/li&gt;&lt;li&gt;Supports copying (to increment the count) and RAII cleanup.&lt;/li&gt;&lt;li&gt;Mimics Rust&amp;rsquo;s immutability by providing const access (mutation would need a separate mechanism).&lt;/li&gt;&lt;li&gt;Avoids atomic operations, matching Rc&amp;rsquo;s single-threaded design.&lt;/li&gt;&lt;/ul&gt;Here&amp;rsquo;s the code:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;
#include &amp;lt;cassert&amp;gt;&lt;br /&gt;#include &amp;lt;utility&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;// Control block to hold the reference count and the value&lt;br /&gt;template &amp;lt;typename T&amp;gt;&lt;br /&gt;struct RcControlBlock {&lt;br /&gt;    size_t count;&lt;br /&gt;    T value;&lt;br /&gt;&lt;br /&gt;    template &amp;lt;typename... Args&amp;gt;&lt;br /&gt;    RcControlBlock(Args&amp;amp;&amp;amp;... args) : count(1), value(std::forward&amp;lt;Args&amp;gt;(args)...) {}&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;template &amp;lt;typename T&amp;gt;&lt;br /&gt;class Rc {&lt;br /&gt;private:&lt;br /&gt;    RcControlBlock&amp;lt;T&amp;gt;* block;&lt;br /&gt;&lt;br /&gt;    // Private constructor from raw block (for internal use)&lt;br /&gt;    explicit Rc(RcControlBlock&amp;lt;T&amp;gt;* b) : block(b) {}&lt;br /&gt;&lt;br /&gt;    void increment() {&lt;br /&gt;        if (block) {&lt;br /&gt;            ++block-&amp;gt;count;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    void decrement() {&lt;br /&gt;        if (block &amp;amp;&amp;amp; --block-&amp;gt;count == 0) {&lt;br /&gt;            delete block;&lt;br /&gt;            block = nullptr;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;public:&lt;br /&gt;    // Constructor: Allocate and construct T&lt;br /&gt;    template &amp;lt;typename... Args&amp;gt;&lt;br /&gt;    explicit Rc(Args&amp;amp;&amp;amp;... args) : block(new RcControlBlock&amp;lt;T&amp;gt;(std::forward&amp;lt;Args&amp;gt;(args)...)) {}&lt;br /&gt;&lt;br /&gt;    // Destructor: Decrease count, cleanup if last reference&lt;br /&gt;    ~Rc() {&lt;br /&gt;        decrement();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Copy constructor: Share ownership&lt;br /&gt;    Rc(const Rc&amp;amp; other) : block(other.block) {&lt;br /&gt;        increment();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Copy assignment: Share ownership&lt;br /&gt;    Rc&amp;amp; operator=(const Rc&amp;amp; other) {&lt;br /&gt;        if (this != &amp;amp;other) {&lt;br /&gt;            decrement();           // Drop old reference&lt;br /&gt;            block = other.block;   // Take new reference&lt;br /&gt;            increment();&lt;br /&gt;        }&lt;br /&gt;        return *this;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Move constructor: Transfer pointer, no count change&lt;br /&gt;    Rc(Rc&amp;amp;&amp;amp; other) noexcept : block(other.block) {&lt;br /&gt;        other.block = nullptr; // Leave moved-from empty&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Move assignment: Transfer pointer, no count change&lt;br /&gt;    Rc&amp;amp; operator=(Rc&amp;amp;&amp;amp; other) noexcept {&lt;br /&gt;        if (this != &amp;amp;other) {&lt;br /&gt;            decrement();           // Drop old reference&lt;br /&gt;            block = other.block;   // Take new reference&lt;br /&gt;            other.block = nullptr; // Leave moved-from empty&lt;br /&gt;        }&lt;br /&gt;        return *this;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Accessors (const only, mimicking Rust's immutability)&lt;br /&gt;    const T&amp;amp; operator*() const {&lt;br /&gt;        assert(block != nullptr);&lt;br /&gt;        return block-&amp;gt;value;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    const T* operator-&amp;gt;() const {&lt;br /&gt;        assert(block != nullptr);&lt;br /&gt;        return &amp;amp;block-&amp;gt;value;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Clone method (like Rc::clone)&lt;br /&gt;    Rc clone() const {&lt;br /&gt;        return Rc(*this); // Uses copy constructor&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Get reference count (for debugging)&lt;br /&gt;    size_t use_count() const {&lt;br /&gt;        return block ? block-&amp;gt;count : 0;&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;// Factory function (like Rc::new)&lt;br /&gt;template &amp;lt;typename T, typename... Args&amp;gt;&lt;br /&gt;Rc&amp;lt;T&amp;gt; make_rc(Args&amp;amp;&amp;amp;... args) {&lt;br /&gt;    return Rc&amp;lt;T&amp;gt;(std::forward&amp;lt;Args&amp;gt;(args)...);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;This Rc&amp;lt;T&amp;gt; captures Rust&amp;rsquo;s essence - shared, immutable, single-threaded ownership.&lt;br /&gt;&lt;div&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://vak.dreamwidth.org/1354705.html#cutid1"&gt;объяснения&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1354705" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1354391</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1354391.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1354391"/>
    <title>Что такое Result&amp;lt;T, E&amp;gt;</title>
    <published>2025-02-27T21:31:58Z</published>
    <updated>2025-02-27T21:41:40Z</updated>
    <category term="программистское"/>
    <category term="c++"/>
    <category term="rust"/>
    <dw:security>public</dw:security>
    <dw:reply-count>16</dw:reply-count>
    <content type="html">Есть в Rust популярная идиома: Result&amp;lt;(), String&amp;gt;. Используется для функций, которые в случае успехи ничего не возвращают, а в случае ошибки возвращают текстовую строку. К примеру, копирование одного файла в другой из реального проекта:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;
fn copy_file_contents(mut dest_file: &amp;amp;fs::File, src_filename: &amp;amp;str) -&amp;gt; &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;em&gt;&lt;strong&gt;Result&amp;lt;(), String&amp;gt;&lt;/strong&gt;&lt;/em&gt;&lt;/span&gt; {&lt;br /&gt;    let mut src_file = fs::File::open(src_filename)&lt;br /&gt;                                .map_err(|e| format!(&amp;quot;Failed to open source file '{}': {}&amp;quot;, src_filename, e))?;&lt;br /&gt;    io::copy(&amp;amp;mut src_file, &amp;amp;mut dest_file)&lt;br /&gt;       .map_err(|e| format!(&amp;quot;Failed to copy to destination: {}&amp;quot;, e))?;&lt;br /&gt;    Ok(())&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;Давайте попросим grok.com сделать аналогичный класс на Си++.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;em&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;Question:&lt;/span&gt;&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;&lt;span style="color: rgb(51, 153, 102);"&gt; There is a popular idiom: Result&amp;lt;(), String&amp;gt;. I would like to see how it could be implemented in C++.&lt;/span&gt;&lt;/em&gt;&lt;br /&gt;&lt;blockquote&gt;Let&amp;rsquo;s dive into translating the Rust idiom Result&amp;lt;(), String&amp;gt; into C++. In Rust, Result is an enum used for error handling, with two variants: Ok(T) for success and Err(E) for failure. Here, Result&amp;lt;(), String&amp;gt; means a function returns either &amp;quot;success with no meaningful value&amp;quot; (Ok(()), where () is the unit type) or &amp;quot;failure with a string error message&amp;quot; (Err(String)). This is a common pattern in Rust for operations that either succeed without producing a value or fail with a descriptive error.&lt;br /&gt;&lt;br /&gt;In C++, we don&amp;rsquo;t have a direct equivalent to Rust&amp;rsquo;s Result in the standard library, but we can approximate it using modern C++ features. The closest analogs are std::optional, std::variant, or a custom implementation.&lt;br /&gt;&lt;br /&gt;Let&amp;rsquo;s define a reusable Result class with a Rust-like interface, using std::variant under the hood. This adds convenience methods like is_ok(), is_err(), unwrap(), and unwrap_err().&lt;br /&gt;&lt;pre&gt;
#include &amp;lt;variant&amp;gt;&lt;br /&gt;#include &amp;lt;string&amp;gt;&lt;br /&gt;#include &amp;lt;stdexcept&amp;gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;&lt;br /&gt;template&amp;lt;typename T, typename E&amp;gt;&lt;br /&gt;class Result {&lt;br /&gt;public:&lt;br /&gt;    Result(T value) : data(value) {}&lt;br /&gt;    Result(E error) : data(error) {}&lt;br /&gt;&lt;br /&gt;    bool is_ok() const { return std::holds_alternative&amp;lt;T&amp;gt;(data); }&lt;br /&gt;    bool is_err() const { return std::holds_alternative&amp;lt;E&amp;gt;(data); }&lt;br /&gt;&lt;br /&gt;    T unwrap() const {&lt;br /&gt;        if (is_err()) throw std::runtime_error(&amp;quot;Called unwrap() on an Err value&amp;quot;);&lt;br /&gt;        return std::get&amp;lt;T&amp;gt;(data);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    E unwrap_err() const {&lt;br /&gt;        if (is_ok()) throw std::runtime_error(&amp;quot;Called unwrap_err() on an Ok value&amp;quot;);&lt;br /&gt;        return std::get&amp;lt;E&amp;gt;(data);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;private:&lt;br /&gt;    std::variant&amp;lt;T, E&amp;gt; data;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;// Specialize for empty value and std::string&lt;br /&gt;struct Void {};&lt;br /&gt;using VoidResult = Result&amp;lt;Void, std::string&amp;gt;;&lt;br /&gt;&lt;/pre&gt;This version is the most Rust-like. VoidResult directly corresponds to Result&amp;lt;(), String&amp;gt;. You can call is_ok() or is_err() to check the state, and unwrap() or unwrap_err() to extract values (with error checking). It&amp;rsquo;s reusable for other T and E types too.&lt;br /&gt;&lt;/blockquote&gt;А вот пример использования такого класса, тоже сгенерённый Гроком.&lt;br /&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://vak.dreamwidth.org/1354391.html#cutid1"&gt;Си++&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;Вполне&amp;nbsp;разумная вещь получилась. Можно использовать в разных Си++ проектах. Полный исходник лежит здесь: &lt;a href="https://github.com/sergev/vak-opensource/blob/master/languages/c%2B%2B/result.cpp"&gt;result.cpp&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1354391" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1353624</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1353624.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1353624"/>
    <title>Перепишем Box&amp;lt;T&amp;gt; на Си++</title>
    <published>2025-02-26T22:58:55Z</published>
    <updated>2025-02-27T07:46:17Z</updated>
    <category term="rust"/>
    <category term="c++"/>
    <category term="программистское"/>
    <dw:security>public</dw:security>
    <dw:reply-count>15</dw:reply-count>
    <content type="html">Нет лучше способа понять язык программирования, чем глянуть на реализацию. В языке Rust многое напоминает Си++, но всё ж таки &amp;quot;трошечки не так&amp;quot;. Разберёмся с конструкцией Box&amp;lt;T&amp;gt; для начала. Спросим grok.com. Результат смотрите в файле &lt;a href="https://github.com/sergev/vak-opensource/blob/master/languages/c%2B%2B/box.cpp"&gt;box.cpp&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;em&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;Question:&lt;/span&gt;&lt;/em&gt;&lt;/strong&gt;&lt;em&gt;&lt;span style="color: rgb(51, 153, 102);"&gt; Imagine I need to re-implement Box&amp;lt;T&amp;gt; in C++. How would it look like?&lt;br /&gt;&lt;/span&gt;&lt;/em&gt;&lt;br /&gt;Re-implementing Rust&amp;rsquo;s Box&amp;lt;T&amp;gt; in C++ is a fun challenge that lets us peek into Rust&amp;rsquo;s memory management internals and translate them into C++&amp;rsquo;s world. In Rust, Box&amp;lt;T&amp;gt; is a smart pointer that provides heap-allocated ownership with automatic cleanup, backed by the global allocator (usually malloc/free via Rust&amp;rsquo;s alloc crate). It&amp;rsquo;s simple but powerful: it allocates memory for a T, moves the value onto the heap, and deallocates it when the Box goes out of scope via Drop. In C++, we don&amp;rsquo;t have Rust&amp;rsquo;s ownership model or Drop trait, so we&amp;rsquo;ll use RAII and a custom class to mimic it.&lt;br /&gt;&lt;br /&gt;Let&amp;rsquo;s design a C++ equivalent, breaking down the essentials of Box&amp;lt;T&amp;gt; and handling the nuances of C++&amp;rsquo;s memory model.&lt;br /&gt;&lt;h3&gt;What Box&amp;lt;T&amp;gt; Does in Rust&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Allocation: Allocates memory on the heap for a T using the global allocator.&lt;/li&gt;&lt;li&gt;Ownership: Sole owner of the heap memory; no sharing or borrowing by default.&lt;/li&gt;&lt;li&gt;Move Semantics: Transfers ownership when assigned or passed (no copying unless T: Clone).&lt;/li&gt;&lt;li&gt;Deallocation: Automatically frees the memory when dropped, calling T&amp;rsquo;s destructor if it has one.&lt;/li&gt;&lt;li&gt;Dereferencing: Provides access to T via * or . (through Deref).&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;C++ Implementation&lt;/h3&gt;We&amp;rsquo;ll create a Box class in C++ that:&lt;ul&gt;&lt;li&gt;Uses new and delete for allocation/deallocation (mirroring malloc/free).&lt;/li&gt;&lt;li&gt;Implements RAII for automatic cleanup.&lt;/li&gt;&lt;li&gt;Supports move semantics (C++11 and later) to mimic Rust&amp;rsquo;s ownership transfer.&lt;/li&gt;&lt;li&gt;Prevents copying to enforce single ownership (like Rust).&lt;/li&gt;&lt;li&gt;Provides dereference operators (* and -&amp;gt;).&lt;/li&gt;&lt;/ul&gt;Here&amp;rsquo;s the code: &lt;a href="https://github.com/sergev/vak-opensource/blob/master/languages/c%2B%2B/box.cpp"&gt;box.cpp&lt;/a&gt;.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;
template &amp;lt;typename T&amp;gt;&lt;br /&gt;class Box {&lt;br /&gt;private:&lt;br /&gt;    T *ptr; // Raw pointer to heap-allocated memory&lt;br /&gt;&lt;br /&gt;    // Private helper to deallocate&lt;br /&gt;    void deallocate()&lt;br /&gt;    {&lt;br /&gt;        if (ptr) {&lt;br /&gt;            delete ptr; // Calls T's destructor, then frees memory&lt;br /&gt;            ptr = nullptr;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;public:&lt;br /&gt;    // Constructor: Allocate and construct T in-place&lt;br /&gt;    template &amp;lt;typename... Args&amp;gt;&lt;br /&gt;    explicit Box(Args &amp;amp;&amp;amp;...args) : ptr(new T(std::forward&amp;lt;Args&amp;gt;(args)...))&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Destructor: Automatically clean up&lt;br /&gt;    ~Box() { deallocate(); }&lt;br /&gt;&lt;br /&gt;    // Disable copying (Rust Box doesn't allow this)&lt;br /&gt;    Box(const Box &amp;amp;) = delete;&lt;br /&gt;    Box &amp;amp;operator=(const Box &amp;amp;) = delete;&lt;br /&gt;&lt;br /&gt;    // Move constructor: Transfer ownership&lt;br /&gt;    Box(Box &amp;amp;&amp;amp;other) noexcept : ptr(other.ptr)&lt;br /&gt;    {&lt;br /&gt;        other.ptr = nullptr; // Leave other in a valid, empty state&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Move assignment: Transfer ownership&lt;br /&gt;    Box &amp;amp;operator=(Box &amp;amp;&amp;amp;other) noexcept&lt;br /&gt;    {&lt;br /&gt;        if (this != &amp;amp;other) {&lt;br /&gt;            deallocate();        // Free current memory&lt;br /&gt;            ptr = other.ptr;     // Take ownership&lt;br /&gt;            other.ptr = nullptr; // Leave other empty&lt;br /&gt;        }&lt;br /&gt;        return *this;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // Dereference operators&lt;br /&gt;    T &amp;amp;operator*() { return *ptr; }&lt;br /&gt;    const T &amp;amp;operator*() const { return *ptr; }&lt;br /&gt;&lt;br /&gt;    T *operator-&amp;gt;() { return ptr; }&lt;br /&gt;    const T *operator-&amp;gt;() const { return ptr; }&lt;br /&gt;&lt;br /&gt;    // Optional: Raw pointer access (like Box::into_raw in Rust)&lt;br /&gt;    T *as_raw() { return ptr; }&lt;br /&gt;&lt;br /&gt;    // Optional: Take ownership back (like Box::from_raw, but consumes self)&lt;br /&gt;    T into_inner()&lt;br /&gt;    {&lt;br /&gt;        T value = std::move(*ptr);&lt;br /&gt;        deallocate();&lt;br /&gt;        return value;&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;// Factory function to simplify creation (like Box::new in Rust)&lt;br /&gt;template &amp;lt;typename T, typename... Args&amp;gt;&lt;br /&gt;Box&amp;lt;T&amp;gt; make_box(Args &amp;amp;&amp;amp;...args)&lt;br /&gt;{&lt;br /&gt;    return Box&amp;lt;T&amp;gt;(std::forward&amp;lt;Args&amp;gt;(args)...);&lt;br /&gt;}&lt;/pre&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://vak.dreamwidth.org/1353624.html#cutid1"&gt;объяснения&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1353624" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1353337</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1353337.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1353337"/>
    <title>Изучаем Rust с помощью ИИ</title>
    <published>2025-02-26T22:03:48Z</published>
    <updated>2025-03-03T05:05:14Z</updated>
    <category term="программистское"/>
    <category term="rust"/>
    <category term="c++"/>
    <dw:security>public</dw:security>
    <dw:reply-count>4</dw:reply-count>
    <content type="html">Стал я пробовать grok.com вместо gemini.google.com, и надо сказать, прогресс заметный. Я в основном пристаю к ИИ на тему программирования. Здесь Grok на голову выше Gemini, как отличник супротив троечника. Поделюсь с вами одним примером. Я спросил про smart указатели в Rust, и Grok прочитал мне целую лекцию. Первые пять в списке действительно smart указатели, а остальные скорее smart контейнеры. Но всё равно хорошо.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;&lt;em&gt;Question:&lt;/em&gt;&lt;/span&gt;&lt;/strong&gt;&lt;span style="color: rgb(51, 153, 102);"&gt;&lt;em&gt; How many smart pointers like Box and Rc are present in Rust?&lt;/em&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Rust&amp;rsquo;s standard library offers a rich set of smart pointers beyond Box&amp;lt;T&amp;gt; and Rc&amp;lt;T&amp;gt;, each tailored to specific ownership semantics, threading needs, and use cases. These smart pointers leverage Rust&amp;rsquo;s ownership model and type system to provide safe, ergonomic memory management. Let&amp;rsquo;s count and explore them, focusing on the main ones in std (and one notable exception from alloc). I&amp;rsquo;ll cover their purposes and how they fit into Rust&amp;rsquo;s ecosystem.&lt;br /&gt;&lt;h3&gt;Smart Pointers in Rust&amp;rsquo;s Standard Library&lt;/h3&gt;Here are the primary smart pointers in Rust, all from std unless noted:&lt;br /&gt;&lt;br /&gt;1. &lt;a href="https://vak.dreamwidth.org/1353624.html"&gt;Box&amp;lt;T&amp;gt;&lt;/a&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Module: std::boxed&lt;/li&gt;&lt;li&gt;Purpose: &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;em&gt;&lt;strong&gt;Unique&lt;/strong&gt;&lt;/em&gt;&lt;/span&gt; ownership of a heap-allocated T. The simplest smart pointer, providing a single owner with automatic cleanup.&lt;/li&gt;&lt;li&gt;Use Case: When you need heap allocation without sharing (e.g., recursive data structures, large objects).&lt;/li&gt;&lt;li&gt;Threading: Safe to send across threads if T: Send.&lt;/li&gt;&lt;/ul&gt;2. &lt;a href="https://vak.dreamwidth.org/1354705.html"&gt;Rc&amp;lt;T&amp;gt;&lt;/a&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Module: std::rc&lt;/li&gt;&lt;li&gt;Purpose: Reference-counted &lt;span style="color: rgb(255, 0, 0);"&gt;&lt;em&gt;&lt;strong&gt;shared&lt;/strong&gt;&lt;/em&gt;&lt;/span&gt; ownership for single-threaded use. Multiple Rc&amp;lt;T&amp;gt; instances share the same T, deallocating when the last reference drops.&lt;/li&gt;&lt;li&gt;Use Case: Shared immutable data in a single thread (e.g., graph structures).&lt;/li&gt;&lt;li&gt;Threading: Not thread-safe (!Send, !Sync).&lt;/li&gt;&lt;li&gt;Notes: Paired with Weak&amp;lt;T&amp;gt; for non-owning refs.&lt;/li&gt;&lt;/ul&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://vak.dreamwidth.org/1353337.html#cutid1"&gt;also Arc, Weak, Cell, RefCell, Mutex, RwLock, Cow&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;h3&gt;Comparison to C++&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;C++ Equivalents:&lt;ul&gt;&lt;li&gt;Box&amp;lt;T&amp;gt; &amp;asymp; std::unique_ptr&amp;lt;T&amp;gt;&lt;/li&gt;&lt;li&gt;Rc&amp;lt;T&amp;gt; &amp;asymp; std::shared_ptr&amp;lt;T&amp;gt; (non-atomic version)&lt;/li&gt;&lt;li&gt;Arc&amp;lt;T&amp;gt; &amp;asymp; std::shared_ptr&amp;lt;T&amp;gt; (atomic)&lt;/li&gt;&lt;li&gt;Weak&amp;lt;T&amp;gt; &amp;asymp; std::weak_ptr&amp;lt;T&amp;gt;&lt;/li&gt;&lt;li&gt;Mutex&amp;lt;T&amp;gt; &amp;asymp; std::mutex + std::unique_lock&lt;/li&gt;&lt;li&gt;RwLock&amp;lt;T&amp;gt; &amp;asymp; std::shared_mutex (C++17)&lt;/li&gt;&lt;li&gt;No direct Cell/RefCell - custom runtime checks needed.&lt;/li&gt;&lt;li&gt;Cow &amp;asymp; custom variant-like type or manual ownership toggling.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Rust Unique: Cell and RefCell leverage Rust&amp;rsquo;s borrow checker, offering safety not easily replicated in C++.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1353337" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1352881</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1352881.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1352881"/>
    <title>Текстовый редактор на Rust</title>
    <published>2025-02-25T18:36:07Z</published>
    <updated>2025-02-25T20:00:54Z</updated>
    <category term="искусственный интеллект"/>
    <category term="программистское"/>
    <category term="rust"/>
    <dw:security>public</dw:security>
    <dw:reply-count>0</dw:reply-count>
    <content type="html">Программировать с помощью ИИ становится прикольно. Зашёл на x.ai и попросил написать простой текстовый редактор типа emacs. Вполне неплохой код получился. Создаём файл src/main.rs:&lt;br /&gt;&lt;div&gt;&lt;span class="cut-wrapper"&gt;&lt;span style="display: none;" id="span-cuttag___1" class="cuttag"&gt;&lt;/span&gt;&lt;b class="cut-open"&gt;(&amp;nbsp;&lt;/b&gt;&lt;b class="cut-text"&gt;&lt;a href="https://vak.dreamwidth.org/1352881.html#cutid1"&gt;Исходники&lt;/a&gt;&lt;/b&gt;&lt;b class="cut-close"&gt;&amp;nbsp;)&lt;/b&gt;&lt;/span&gt;&lt;div style="display: none;" id="div-cuttag___1" aria-live="assertive"&gt;&lt;/div&gt;&lt;/div&gt;Компилируем, запускаем - работает!&lt;blockquote&gt;&lt;pre&gt;cargo run
&lt;/pre&gt;&lt;/blockquote&gt;&lt;img src="https://vak.dreamwidth.org/file/1651054.png" alt="" /&gt;&lt;br /&gt;Это я туда некий текст скопипастил. Выход по ^C. С таким помощником удобно язык изучать.&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1352881" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
  <entry>
    <id>tag:dreamwidth.org,2016-12-25:2601916:1307392</id>
    <link rel="alternate" type="text/html" href="https://vak.dreamwidth.org/1307392.html"/>
    <link rel="self" type="text/xml" href="https://vak.dreamwidth.org/data/atom/?itemid=1307392"/>
    <title>Как учить язык программирования Rust</title>
    <published>2024-12-03T04:01:51Z</published>
    <updated>2024-12-03T04:03:59Z</updated>
    <category term="rust"/>
    <category term="познавательное"/>
    <category term="программистское"/>
    <dw:security>public</dw:security>
    <dw:reply-count>4</dw:reply-count>
    <content type="html">&lt;a href="https://github.com/pretzelhammer/rust-blog/blob/master/posts/learning-rust-in-2024.md"&gt;github.com/pretzelhammer/rust-blog/blob/master/posts/learning-rust-in-2024.md&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;“After a short 19 to 30 hours you'll go from being a Rust beginner to a Rust advanced beginner.” 😀&lt;br /&gt;&lt;br /&gt;&lt;img src="https://www.dreamwidth.org/tools/commentcount?user=vak&amp;ditemid=1307392" width="30" height="12" alt="comment count unavailable" style="vertical-align: middle;"/&gt; comments</content>
  </entry>
</feed>
