スポンサーリンク

Rust 参照と借用をC++と比較して確認

参照

Rust版

Rustでは、値を変更できる参照は一度に一つしか作れない。

struct structAB {
  v:i32,
}


fn main() {

    let mut oo=structAB{v:5};

    let _r:&mut structAB = &mut oo; // OK
    let _g:&mut structAB = &mut oo; // NG 可変の参照。二つ目以降は作れない
    let _b:&mut structAB = &mut oo; // NG 

    _r.v=2;
    _g.v=1; // NG そもそも定義できない
    _b.v=0; // NG そもそも定義できない


}

immutableな参照であればいくつでも作れる。

struct structAB {
  v:i32,
}


fn main() {

    let mut oo=structAB{v:5};

    let _r:&structAB = &oo; // OK
    let _g:&structAB = &oo; // OK &mut でなければいくつでも作れる
    let _b:&structAB = &oo; // OK 

    let r = _r.v; // OK 読み取りはできる
    let g = _g.v; // ただし 書き換えられない。
    let b = _b.v; // 

}

C++で類似コード

Rustの参照は制限がきつく間違った使い方をコンパイラがはじいてくれるweak_ptrと考えるとC++erにとってはわかりやすいかもしれない。

#include <iostream>
#include <memory>

struct StructAB {
    int v;
    StructAB(int a) :v(a) {}
};

int main()
{
    auto oo = std::make_shared<StructAB>(5);

    // C++ では所有権を持たない参照をいくつでも参照を作れる
    std::weak_ptr<StructAB> _r = oo;
    std::weak_ptr<StructAB> _g = oo; // Rustではエラー
    std::weak_ptr<StructAB> _b = oo; // 二つ目以降の可変な参照を作れない

    _r.lock()->v = 2;
    _g.lock()->v = 1; // Rustではエラー
    _b.lock()->v = 0; // Rustではエラー

}

借用

借用はC++でいうところのmove。問題は、Rustの場合、(プリミティブ型以外)=代入の挙動がデフォルトでmoveになっていることで、「operator=は常にコピーであることが望ましい」というC++の哲学とは全く相いれない。

Rust版

struct structAB {
  v:i32,
}

fn main() {

    let oo=structAB{v:5};

    let pp = oo; // ただの=がmoveになる
    
    println!("{} => {}",oo.v , pp.v);// value borrowed here after move  (ooが無効)

}

C++で類似コード

#include <iostream>
#include <memory>

struct StructAB {
    int v;
    StructAB(int a) :v(a) {}
};

int main()
{
    auto oo = std::make_unique<StructAB>(5);

    auto pp = std::move(oo); // ここでmoveすると以降ooはnullptr

    printf("%d => %d\n", oo->v,pp->v); // ランタイムエラー (ooがnullptr)

}

それどころか、引数渡しですらデフォルトでmoveなので、迂闊に渡すとライフタイムが切れてしまう。

Rust版

struct structAB {
  v:i32,
}


fn test(ii:structAB)->i32{
  
  return ii.v*2;

  // ii はここで解放される
}
fn main() {

    let oo=structAB{v:5};

    let pp = test(oo); // ここで oo がmoveされてしまうので、test関数から抜けた段階でライフタイムが切れる

    println!("{} => {}",oo.v , pp);

}

C++で類似コード

#include <iostream>
#include <memory>

struct StructAB {
    int v;
    StructAB(int a) :v(a) {}
};

int test(std::unique_ptr<StructAB> ii) {
    
    return ii->v * 2;

    // ii はここでデストラクトされる
}
int main()
{
    auto oo = std::make_unique<StructAB>(5);

    auto pp = test(std::move(oo)); // ここでmoveすると以降ooはnullptr

    printf("%d => %d\n", oo->v,pp);

}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: