• 作成:

Rustは実行時オーバーヘッドを生じさせないという意味でやっと出てきたC++の後継言語です

RustをOCamlなどの仲間だと勘違いしている人は居るでしょうか. 私がそうでした. しかしRustはC++の後継言語です.

C++は言語レベルのGCを持ちません. つまり実行時オーバーヘッドはプログラマが選択しない限り発生しません.

C++の問題点

C++の有名な問題点は, ポインタの寿命が把握できないことです.

#include <iostream>
#include <memory>
#include <vector>
int main() {
    std::vector<int> v = {0};
    auto p = v.begin();
    for(int i = 1; i < 100; ++i) {
        v.push_back(i);
    }
    std::cout << *p << std::endl;
}

このコードはおそらく0を出力してくれません. それはvectorがメモリ上で再確保されて… みなさん原理は知っていますよね.

もちろんC++でもこの現象を回避することはできます. 参照カウントGCを使うことです.

GCによる回避

#include <iostream>
#include <memory>
#include <vector>
int main() {
    std::vector<std::shared_ptr<int>> v = {std::make_shared<int>(0)};
    std::shared_ptr<int> p = *v.begin();
    for(int i = 1; i < 100; ++i) {
        v.push_back(std::make_shared<int>(i));
    }
    std::cout << *p << std::endl;
}

こうすればきちんと0を出力してくれます. GCを使ってみんなポインタにすれば, ポインタの寿命問題はなくなります.

これを言語レベルで簡単にしているのがLisp, Java, C#などの言語です. しかし, これは根本的な解決にはなっていません. 実行時オーバーヘッドが生じるからです.

特にゲーム業界のみなさんはJavaやC#のGCの制御に苦労していらっしゃいます. カプコンなどC#のGCを独自に実装するほどです. D言語にも色々なオプションがあります.

GCはオーバーヘッドが大変です.

Rustによる解決策

Rustはこの問題を別の方法で解決します. ポインタの寿命がはっきりしないようなコードはコンパイルを失敗させます. つまり, 最初に出したようなコードはRustでは書いてもコンパイルが失敗するのです. 原理は寿命管理がどうのこうのなんですがそんなことは実用にはどうでも良いでしょう. これで, C++の危険性を含む問題点は解決されました.

おまけ

RustでもC++のshared_ptrのような参照カウントGCは使うことができます.

use std::rc::Rc;
fn main() {
    let mut v = vec![Rc::new(0)];
    let p = v[0].clone();
    for i in 1..100 {
        v.push(Rc::new(i));
    }
    println!("{}", p);
}