The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]



"Опрос Stack Overflow: Rust назван самым любимым, а Python самым востребованным языком"
Версия для распечатки Пред. тема | След. тема
Форум Разговоры, обсуждение новостей
Исходное сообщение [ Отслеживать ]
Заметили полезную информацию ? Пожалуйста добавьте в FAQ на WIKI.
. "Опрос Stack Overflow: Rust назван самым любимым, а Python са..." +1 +/
Сообщение от Ordu (ok), 06-Авг-21, 14:49 
>> Насколько я понимаю в пайтоне единственная стратегия управления памятью -- сборка мусора.
> Мда, неудачный пример.
> Кстати, а вообще в расте это используется (т.е. в std)?

Какие стратегии в принципе есть? Сборка мусора. Подсчёт ссылок. Или какие-то вручную выстроенные, например, мы на каком-то стековом фрейме выделяем память, а все верхние стековые фреймы работают с этой памятью как со статической, не выделяя или парясь освобождать. Ну, чтоб конкретный пример, допустим у нас есть груда текста в каком-то синтаксисе, мы парсим и может что-то ещё по-мелочи делаем. Как?

Можно весь текст прочитать из файла в буфер, выделив память, прокинуть в функцию парсинга, и та будет считать что буфер существует столько, сколько надо, брать оттуда токены подстроками, не выделяя под них память, жонглировать ими как угодно, не освобождать память и делать всё что надо. Это тоже своего рода стратегия, мы накладываем на парсер определённые правила работы с памятью, с тем чтобы сделать менеджмент памятью тривиальным, а значит с минимумом ошибок.

Но внезапно оказывается, что подстроки (скажем идентификаторы) надо заносить в AST, и AST должен оставаться валидным и после того, как буфер с исходным текстом будет освобождён. Эммм... Ну ок, мы будем прежде чем заносить в AST делать strndup, то есть будем выделять память. Стратегия становится сложнее...

Но тут мы задумываемся о том, что вовсе не нужно на каждое вхождение идентификатора делать новый strndup, надо на каждый идентификатор делать это единожды. Значит перед strndup надо попытаться найти существующий идентификатор с таким именем, и strndup'ить только если он не найден. Стратегия становится ещй сложнее...

А потом вдруг выяснится, что вот тут надо не просто с подстрокой поработать, а хотелось бы её модифицировать, а потом поработать. Но если мы сделаем так, и если подстрока -- это ссылка внутрь буфера со всем исходным текстом, то мы модифицируем буфер, хотя мы до сих пор писали программу исходя из предположения, что буфер неизменен. Можно рискнуть и изменить, но очень возможно что где-нибудь вылезет странный трудноуловимый баг. Можно сделать на подстроку strndup, модифицировать копию, и поработать с ней. Но надо не забыть освободить потом память. Стратегия становится ещё сложнее...

В стратегии появляются усложнения, дополнения, исключения, и в некоторых случаях она может превращаться в что-то невыразимое словами. Чем сложнее стратегия, тем сложнее ей следовать, тем более вероятны баги. Когда я прочитал какую-то книжку про структуры данных, я был восхищён без меры, и первым делом я запилил такую структуру данных, что... Мне повезло, что тогда я уже сидел в венде, а не в DOS'е, потому что программа падала постоянно, в DOS'е я бы замучался перезагружаться. И никакие объёмы отладки не могли исправить все баги. Потом в моей практике подобное случалось ещё пару раз.

В расте это не проблема, потому что borrowed указатель внутрь неизменяемого буфера отличается от owned указателя, эта разница отслеживается статически, и если я позволяю себе делать с borrowed что-то, что с ним нельзя делать, компилятор будет ругаться. В расте я могу, скажем, для строк-идентификаторов завести специальную кучу -- это может быть просто HashSet, например, чтобы закидывать туда идентификаторы, -- и получить (или может создать вручную) специальный тип указателя, который будет жить немного по своим законам. Типа указатель на идентификатор вроде и borrowed, но используется так же просто как указатель на статическую память -- делай что хочешь, кроме изменений внутри объекта. По-сути, я описываю свой план менеджмента памятью в своих API, и компилятор потом проверяет, насколько мне удалось этому плану следовать. Я могу сколь угодно угодно сложную стратегию изобретать -- всё что мне удастся закодировать в API, -- и не бояться, что эта стратегия слишком сложна для меня, что у меня процессорной мощности серого вещества не хватит на неё. (Ну, то есть, может и не хватит, но я не смогу этого не заметить, потому что в этом случае дело кончится некомпилируемым кодом, который мне не удаётся довести до компилируемого состояния. Это будет очень досадно, но это лучше, чем код который компилируется, и падает в рандомные моменты.)

RAII, на фоне этого, выглядит мелким дополнением, которое избавляет меня от необходимости явно писать free. Иногда это не столь мелко, если это даёт возможность писать полиморфный код, который один раз компилируется в код с вызовом free, а другой раз в код без вызова free, в зависимости от того, с каким куском памяти он работает.

Возвращаясь к std: в ней используются все элементы, из которых можно запилить любую такую стратегию. Используется предача borrowed ссылок, используется передача значения с возвратом его из функции (что позволяет функции, например, принять буфер, при необходимости перевыделить его, изменить содержимое и вернуть обратно), передача "указателя на указатель" (если я закидываю в функцию &mut String, чтобы та дописала что-то, при необходимости перевыделяя память, то это аналог передачи (char** s, size_t* len) в C)... Элементы все используются, то есть примеры использования можно найти. Но естественно в ней не используются все возможные такие стратегии, которые можно построить из этих кирпичиков.

>> Есть ведь unsafe
> Не, конечно без.

Строго говоря без unsafe'а совсем не выйдет. Придётся использовать std, а в std есть, например, реализация массива -- slice и Vec, -- а их невозможно реализовать без unsafe: там внутри работа с raw-указателями в C'шном стиле. Но если принять допущение, что std не содержит ошибок, то дальше всё доказывается строго компилятором.

Ответить | Правка | Наверх | Cообщить модератору

Оглавление
Опрос Stack Overflow: Rust назван самым любимым, а Python самым востребованным языком, opennews, 04-Авг-21, 09:26  [смотреть все]
Форумы | Темы | Пред. тема | След. тема



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру