ZigのArrayListにポインタ安定性ロックが追加、メモリ安全性を向上
Zig: Pointer Stability for ArrayLists
Zigの標準ライブラリに、ArrayListのポインタ安定性を保証するロック機構が追加された。これは2024年にHashMapに導入された手法をArrayListに拡張したもので、開発者は要素へのポインタを保持する際にlockPointers()を呼び出し、不要になったらunlockPointers()で解放する。これにより、リストの再割り当てによるポインタの無効化を検出し、デバッグを容易にする。実際のバグ例とその修正方法、ArrayList特有の注意点(順序変更操作によるポインタ移動)も解説されている。
ポインタ安定性の前提が破られた場所を、スタックトレース付きのパニックで即座に教えてくれる。
HNでの議論
65- amluto
これは弱いように思えます。
Rustのような言語では、コンパイラがポインタを「ロック」してくれて、忘れることがありません。
C++(そしておそらくZig)のような言語では、理論上は少なくとも、動的配列のストレージを参照するイテレータやスライスに、ストレージを固定する何らかのロックを保持させることができるでしょう。
しかし、このAPIでは、プログラマがポインタをロックすることを覚えておく必要があり、また、正しいコード領域に対してロックを保持し続ける必要があります。そして、私の目には、ブログ記事の例でさえ、ロックが安定性を必要とする関数の完全に外側で取られており、ロックのスコープを正しくするものが何もないように見えます。型システムでさえ助けにはなりません——問題のparse関数は、ポインタロックされたArrayListパラメータを要求することを宣言できません。
- _bohm
素晴らしい機能ですが、コレクション内のアイテムへの安定したポインタが必要なら、ArrayListは間違ったデータ構造ではないかという気がしてなりません。誰か、単にインデックスを保存するのではなく、これを使う例を教えてくれる人はいませんか?あるいは、Unrolled Linked List(Zigでは0.16で削除されるまでSegmentedListと呼ばれていた、なぜ削除されたのかはわかりませんが)を使うこともできるでしょう。
- portly
これは言語の他の部分と一貫していると考えると、非常に理にかなっています。これは、自分のプログラミングエラーを検出するためにコードにトリップワイヤーを仕掛けるもう一つの方法です。関数でアサートを使って入出力を検証するのと似ています。
私はArrayListをよく使うので、これをコード全体に追加して強化できるのは楽しみです。
これが誰にでも好まれるわけではないとは想像できますが、そうでなければ、他の明示性も楽しめないでしょう。
- Rendello
余談:Rustで本当に恋しいZigの(構文)機能が2番目のコードブロックに示されています。それは、次のような接頭辞付きの複数行文字列リテラルです:
const text =
\\これは長いコメントです
\\しかし、行を任意に分割できます
\\そしてインデントを維持できます。
;
私はRustのマクロライブラリ`docstr` [1]を使い始めました。これも同じことをします:
const TEXT: &'static str = docstr!(
/// これでRustでもできます。
/// 長いテキストでは、このスタイルをよく好みます。
);
これはマクロでも動作します(ドキュメントの例):
let greeting: String = docstr!(format!
/// こんにちは、私の名前は{name}です。
/// 私は{}歳です!
age
);
- boricj
コンテナ内のポインタ変更に対するアサートであり、SDLサーフェスのようなデータ構造のロック/アンロックではないと理解するのに少し時間がかかりました。
最近、パスのコンポーネントを反復処理できるカスタムC++コンテナを実装しましたが、std::stringをバックエンドにしていました。インデックスと文字列への参照を保存するだけで、std::stringが変更後に再割り当てされてもイテレータが無効になりません。わずかなコストで、はるかにエラーが少なくなります。