【rust】スマートポインタってなに?

rust

スマートポインタを一言で

値へのアドレスとメタデータを持ち、その値の所有権を持つもの。

スマートポインタの代表例

  • 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>:参照規則を実行時に行うようにする

これらについては、別に記事を書こうと思います。

ありがとうございました。

コメント

タイトルとURLをコピーしました