DerefとDropの概要
スマートポインタの「スマート」とは、単なるポインタに加えて、追加の機能を備えていることを意味します。その多くは、Rustのトレイト(trait)によって実現されており、DerefとDropはその代表例です。
Deref:データへのアクセスを簡潔に
Derefトレイトは、スマートポインタが通常の参照(&)と同様に扱えるようにする仕組みです。これにより、間接参照(*)演算子を使うことなく、ポインタが指す値に直接アクセスできます。
Box型でのDerefの実装例
impl<T: ?Sized> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &T {
&self.value
}
}
このように、derefメソッドを実装することで、MyBox<T>型のインスタンスを通常の参照として扱えるようになります。
暗黙的な型変換のサポート
Rustコンパイラは、Derefトレイトを自動的に適用して、以下のような型変換をサポートします:
- &T から &U(T: Deref<Target=U> の場合)
- &mut T から &mut U(T: DerefMut<Target=U> の場合)
- &mut T から &U(T: Deref<Target=U> の場合)
コード例
use std::ops::Deref;
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &T {
&self.0
}
}
fn main() {
let x = 5;
let y = MyBox::new(x);
assert_eq!(5, *y);
}
Drop:リソースの自動解放
Dropトレイトは、変数がスコープを離れる際に自動的に呼ばれるメソッドを定義します。これにより、ファイルハンドル、メモリ領域、ネットワーク接続などのリソースを安全に解放できます。
Dropの基本的な使い方
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("'{}' のリソースを解放中", self.data);
}
}
fn main() {
{
let _c = CustomSmartPointer { data: String::from("テストデータ") };
}
println!("mainの処理を継続");
}
明示的な解放
Dropトレイトのdropメソッドは直接呼び出すことはできませんが、std::mem::drop関数を使って明示的にリソースを解放できます。
Box型におけるDropの実装
unsafe impl<T: ?Sized> Drop for Box<T> {
fn drop(&mut self) {
let ptr = self.0.as_ptr();
unsafe {
if Layout::for_value_raw(ptr).size() != 0 {
// ヒープ領域の解放処理
}
}
}
}
その他のスマートポインタとDeref/Dropの関係
RefCellとCell
RefCellやCellはDerefを実装していません。そのため、通常の参照のようにアクセスすることはできません。代わりに、borrowやgetなどのメソッドを使用して値にアクセスします。
RcとArc
Rc(参照カウント型スマートポインタ)やArc(スレッドセーフな参照カウント型スマートポインタ)はDerefを実装しているため、通常の参照のように扱えます。
use std::rc::Rc;
fn main() {
let data = Rc::new(vec![1, 2, 3, 4, 5]);
let data_clone = Rc::clone(&data);
println!("データの2番目の値: {}", data_clone[1]);
}