前回 に引き続き、
The Rustnomicon の Implementing Vec
をやってみる。
コード全体は GitHub上のリポジトリ にある。
rustcのバージョンは以下のとおり。
$ rustc --version
rustc 1.25.0-nightly (27a046e93 2018-02-18)
Deallocating
確保したメモリは使わなくなったら解放しなくてはいけない。
Drop for Vec
を実装し、その中で解放処理を書くことにする。
ここでも新しい メモリアロケータAPI を使う。
self.cap == 0
のときはメモリ確保していないので、解放もしなくてよい。
self.cap == 1
のときは、pop()
することで要素をdropし、
Alloc::dealloc_one<T>()
を使う。
それ以外の場合は、すべての要素を順に pop()
することでdropし、
Alloc::dealloc_array<T>()
を呼ぶ。
impl<T> Drop for Vec<T> {
fn drop(&mut self) {
if self.cap == 0 {
return;
}
while let Some(_) = self.pop() {}
unsafe {
if self.cap == 1 {
self.alloc.dealloc_one(self.ptr.as_non_null());
} else {
let e = self.alloc.dealloc_array(self.ptr.as_non_null(), self.cap);
if let Err(e) = e {
self.alloc.oom(e);
}
}
}
}
}
なお、T: !Drop
の場合は pop()
を呼ぶ処理を省略できる。
T: Drop
かどうかは mem::needs_drop()
で判定できる。
if mem::needs_drop::<T>() {
while let Some(_) = self.pop() {}
}
しかし、この最適化を施しても効果はほぼ見られなかった。 LLVMの最適化がかなり強いらしい。
ちなみに、
標準ライブラリの Drop for Vec
の実装 では、
ptr::drop_in_place()
を使って Drop for [T]
にフォールバックしているようだ。