Typed Arenaとdropck

概要: Typed Arenaはdropckの目的を説明するよい例になっている。

Typed ArenaとDrop

以前 Typed Arenaの紹介記事 を書いたが、このソースコードに以下のように Drop の実装を足してみる。

extern crate typed_arena;

use std::cell::RefCell;
use typed_arena::Arena;

struct NodeData<'a> {
    references: RefCell<Vec<Node<'a>>>
}
type Node<'a> = &'a NodeData<'a>;

impl<'a> Drop<'a> for NodeData<'a> {
    fn drop(&mut self) {}
}

fn main() {
    let nodes = Arena::new(); // mut は不要
    let node0 = nodes.alloc(NodeData { references: RefCell::new(vec![]) });
    node0.references.borrow_mut().push(node0);
    let node1 = nodes.alloc(NodeData { references: RefCell::new(vec![]) });
    node0.references.borrow_mut().push(node1);
}

すると、Dropの実装を足しただけなのにコンパイルエラーになる。

これは以前の記事で説明したdropck規則によるものであるが、該当記事で説明した例よりもこちらの例のほうがわかりやすいかもしれない。

不健全性の説明

この例がコンパイルされると何が問題なのか?それは、 node0とnode1のデストラクタは、どちらかが先に呼び出される、という点が関係している。

仮にnode1がnode0よりも先にデストラクトされたとする。この場合node0のデストラクタが呼ばれた時点でnode1のデストラクト処理は完了している。しかしnode0はnode1へのポインタを握っているので、node0のデストラクタの中でnode1の廃墟を探索することができる。もちろんこれらの多くは無効なデータであり、触っただけで爆発するかもしれない、ということになる。

まとめ

Typed Arenaはdropckの目的を説明するよい例になっている。