スマートポインタを一言で
値へのアドレスとメタデータを持ち、その値の所有権を持つもの。
スマートポインタの代表例
- Vec<T>
- String
スマートポインタとして見るVec<T>
Vec<T>は代表的なスマートポインタです。以下のようなポインタとメタデータを持ちます。
- ポインタ:配列の先頭アドレス
- メタデータ:要素の数(len)と確保されているサイズ(capacity)
Vec<i32>の構造を以下の例で見てみます。
fn main() {
let b = Vec::from([0,1,2]);
let b_ptr = b.as_ptr();
println!("elements b: {:?}",b);
println!("b address: {:p}",&b);
println!("first element address: {:?}",b_ptr);
}
実行結果
elements b: [0, 1, 2]
b address: 0x16ce89e10
first element address: 0x600003bbc050
この結果を図にして見ると以下のようになります。
bが束縛されているVecは以下の要素を持っています。
- 配列の先頭アドレスである0x600003bbc050
- 配列の長さであるlen
- 配列のサイズであるcapacity
つまり、スマートポインタの特徴である2つのもの、「ある値のアドレス」と「メタデータ」を持っています。
所有権について
スマートポインタは持っているアドレスが指す値を所有します。所有権については別に記事を書いていますので、馴染みのない方は以下が参考になると思います。
値を所有していることを確認するために、以下のコードを使います。
fn main() {
let b_ptr;
{
let b = Vec::from([0, 1, 2]);
b_ptr = b.as_ptr();
unsafe {
println!("{:?}", b_ptr);
println!("{:?}", *b_ptr);
println!("{:?}", *(b_ptr.add(1)));
println!("{:?}", *(b_ptr.add(2)));
}
}
unsafe {
println!("{:?}", b_ptr);
println!("{:?}", *b_ptr);
println!("{:?}", *(b_ptr.add(1)));
println!("{:?}", *(b_ptr.add(2)));
}
}
実行結果
address : 0x6000034e4050
first element : 0
second element : 1
thired element : 2
address : 0x6000034e4050
first element : -1251458992
second element : 24968
thired element : 2043
bが定義されているスコープ内では、配列の各要素にアクセスすると、期待通りの値を得ることができます。しかし、bが定義されているスコープから出ると、同じアドレスを見ているにも関わらず、値はランダムになってしましました。これはbが配列[0,1,2]を所有しており、bがスコープからでたタイミングで値が破棄されたからです。
ちょっと変わった機能を持つスマートポインタ
スマートポインタの代表はVec<T>だと思いますが、他にもたくさんあります。
- Box<T>:メタデータを持たない
- Rc<T>:参照カウントを用いて複数の所有者を許す
- RefCell<T>:参照規則を実行時に行うようにする
これらについては、別に記事を書こうと思います。
ありがとうございました。
コメント