Zig добавляет блокировку указателей для ArrayList

Zig: Pointer Stability for ArrayLists

В Zig появилась защита от ошибок, связанных с нестабильностью указателей в ArrayList. Новая функция lockPointers() блокирует изменение внутреннего буфера, предотвращая ситуации, когда указатели на элементы становятся недействительными после перераспределения памяти. В статье показан пример, где такая ошибка приводит к порче данных, и объясняется, как блокировка помогает обнаружить проблему на раннем этапе. Также рассматриваются особенности, связанные с упорядоченностью ArrayList.

Проблема в том, что элементы Context.lines.items зависят от местоположения Context.history.items, но это местоположение может измениться, если Context.history потребуется вырасти за пределы текущей ёмкости.
  1. amluto

    Это выглядит слабо.

    В таком языке, как Rust, компилятор сам «блокирует» указатели за вас, и вы не можете забыть об этом.

    В таком языке, как C++ (и, предположительно, Zig), можно было бы, по крайней мере теоретически, сделать так, чтобы итераторы и срезы, ссылающиеся на хранилище динамического массива, содержали некий вид блокировки, которая закрепляет это хранилище.

    Но этот API требует, чтобы программист помнил о необходимости блокировать указатели, а также требует, чтобы программист удерживал блокировку в течение правильной области кода. И мне кажется, что даже в примере из поста в блоге блокировка взята полностью вне функции, которая требует стабильности, так что нет ничего, что могло бы правильно ограничить область блокировки. Даже система типов не может помочь — проблемная функция parse не может объявить, что она хочет параметр ArrayList с заблокированными указателями.

  2. _bohm

    Это хорошая функция, но я не могу избавиться от ощущения, что если вам нужен стабильный указатель на элемент коллекции, то ArrayList — неправильная структура данных для этого? Может, кто-то объяснит, когда вы бы использовали это вместо, например, простого хранения индекса. Альтернативно, можно использовать Unrolled Linked List (ранее известный как SegmentedList в Zig до его удаления в 0.16, не знаю почему).

  3. portly

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

    Я часто использую ArrayList, так что рад добавить это по всему коду, чтобы укрепить его.

    Могу представить, что это не всем по вкусу, но тогда вам, вероятно, не понравится и любая другая явность.

  4. Rendello

    Кстати: одна особенность синтаксиса Zig, которую я действительно упускаю в Rust, показана во втором блоке кода, а именно многострочные строковые литералы с префиксом, например:

    const text =

    \\Это длинный комментарий

    \\Но я могу разбить его на строки произвольно

    \\И сохранить мой отступ.

    ;

    Я начал использовать библиотеку макросов Rust `docstr` [1], которая делает то же самое:

    const TEXT: &'static str = docstr!(

    /// Теперь я могу делать это и в Rust.

    /// Я предпочитаю этот стиль во многих случаях

    /// для длинных текстов.

    );

    Она даже работает с макросами (пример из документации):

    let greeting: String = docstr!(format!

    /// Привет, меня зовут {name}.

    /// Мне {} лет!

    age

    );

    1. https://docs.rs/docstr/latest/docstr/

  5. boricj

    Мне потребовалась минута, чтобы понять, что это проверяет изменение указателя внутри контейнера, а не блокирует/разблокирует структуру данных, как поверхность SDL.

    Недавно я реализовал пользовательский контейнер на C++ для пути, компоненты которого можно было перебирать, основанный на std::string. Я просто храню индексы и ссылку на строку, так что мои итераторы не инвалидируются, если std::string перераспределяется после изменения. Гораздо менее подвержено ошибкам за небольшую дополнительную стоимость.

Ещё за этот день

2026-08-30