3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

🛡️ サンプルで理解する Rust の安全性 — C/C++とは違う世界

Posted at

Rustは「安全性(safety)」を徹底的に追求した言語です。
クラッシュ・メモリリーク・データ競合といった低レイヤーでよくあるバグを、Rustは**コンパイル時に“書けないようにする”**ことで防ぎます。

本記事では、「なぜRustが安全なのか?」を、実際のコード例を通してわかりやすく解説していきます。


🔹 目次

  1. 二重解放 vs 所有権
  2. ダングリングポインタ vs ライフタイム
  3. Nullポインタ vs Option型
  4. データ競合 vs 借用チェック
  5. スレッド安全 vs 所有権とSend/Sync
  6. unsafeとその使いどころ
  7. まとめ

1. 🧨 二重解放を防ぐ:所有権の仕組み

C++の場合(危険なコード)

int* ptr = new int(10);
delete ptr;
delete ptr; // 二重解放 → 未定義動作!

Rustの場合(安全)

fn main() {
    let a = Box::new(10);
    let b = a;
    // println!("{}", a); // ❌ 所有権がbに移動したのでaは使えない(コンパイルエラー)
}

Rustでは所有権が1つしか存在できず、所有権を移動したら元の変数は使えなくなるため、二重解放が起こりません。


2. 🧟 ダングリングポインタを防ぐ:ライフタイム

C/C++の例(使ってはいけない戻り値)

int* getPtr() {
    int x = 10;
    return &x; // スタックの寿命を超えてポインタが返る
}

Rustではコンパイルエラーになる!

fn get_ref() -> &i32 {
    let x = 10;
    &x // ❌ コンパイルエラー:xの寿命が短すぎる
}

Rustはライフタイム(寿命)を明示・推論することで、有効期間外の参照を禁止しています。


3. ❓ Nullを防ぐ:Option型による明示的な扱い

C++の場合(nullチェック漏れ)

std::string* ptr = nullptr;
std::cout << ptr->length(); // Segmentation fault!

Rustでは Option<T> で安全に扱う

fn get_name(flag: bool) -> Option<String> {
    if flag {
        Some("Rust".into())
    } else {
        None
    }
}

fn main() {
    match get_name(false) {
        Some(name) => println!("名前: {}", name),
        None => println!("名前なし"),
    }
}

Rustでは「null」は存在しません。「値がある/ない」を型で表現するため、null参照によるクラッシュを根本的に防げます


4. 🔁 データ競合を防ぐ:借用チェッカー

C++なら起こる競合の例

int x = 42;
int* a = &x;
int* b = &x;

*a = 10;
*b = 20; // 同時に書き換え → レースコンディションの原因に

Rustでは可変参照は1つだけ

fn main() {
    let mut x = 42;

    let a = &mut x;
    let b = &mut x; // ❌ エラー:同時に2つの可変参照は不可
}

Rustの借用ルールにより、**「読み取り専用は複数OK」「書き込みは1つだけ」**という制約が守られます。


5. 🧵 スレッド間の安全性:Send / Sync による制御

Rustはスレッドセーフがデフォルトではない(明示)

use std::thread;

fn main() {
    let msg = String::from("hello");

    let handle = thread::spawn(move || {
        println!("{}", msg); // 所有権ごとmoveする必要あり
    });

    handle.join().unwrap();
}
  • Rustではスレッドに渡すデータは Send + Sync のトレイト制約あり
  • 誤って共有メモリを参照するとコンパイルエラーになるため、レースコンディションを防げる

6. 🧯 unsafeって何?なぜ存在する?

Rustの安全性は強力ですが、どうしても以下のようなケースでは「安全チェックを一時的に無効化」したくなることがあります:

  • FFI(C言語との連携)
  • メモリアロケータの実装
  • パフォーマンスの限界に挑むとき
unsafe fn dangerous() {
    println!("unsafeコードです");
}

fn main() {
    unsafe {
        dangerous(); // unsafeブロック内でのみ実行可能
    }
}

→ unsafeは「危険だけど自己責任でやります」という宣言。Rustはその範囲を明示させることで全体の安全性を維持します。


✅ まとめ:Rustは「バグを書けなくする言語」

言語 安全性へのアプローチ
C/C++ バグを避ける or テストで見つける
Java/Python ランタイムで例外にする
Rust コンパイル時にバグを“書けなくする”

Rustの安全性は「面倒そう」に見えても、一度習得すれば大きなバグが激減します。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?