型システム編 - 所有権と借用
難易度: 🔴 上級
所要時間: 40分
📚 この章で学ぶこと
- 所有権システム (Ownership System)
- 移動セマンティクス (Move Semantics)
- 借用 (Borrowing)
- 参照 (References)
所有権とは
Cm言語(v0.11.0以降)では、所有権システムにより、ガベージコレクションなしでメモリ安全性を保証します。
所有権の4つのルール:
- 各値は、ある時点で1つの変数(所有者)だけが所有する
- 所有者がスコープを抜けると、値は破棄される
- 所有権は
moveキーワードで明示的に移動できる - 移動後、元の変数は使用できなくなる
移動セマンティクス (v0.11.0以降)
moveキーワードを使用して、値の所有権を明示的に移動します。
moveキーワードの使用
int main() {
// プリミティブ型も移動可能
int x = 42;
int y = move x; // xの所有権がyへ移動
println("{y}"); // OK: yが値を所有
// println("{x}"); // エラー: xは移動済みで使用不可
// 移動後の再代入も禁止
// x = 50; // エラー: 移動した変数への代入不可
return 0;
}
構造体の移動
struct Box { int value; }
int main() {
Box a = {value: 10};
Box b = move a; // 明示的な移動
println("{}", b.value); // OK: bが所有者
// println("{}", a.value); // エラー: aは移動済み
return 0;
}
コピー vs 移動
プリミティブ型は明示的に移動しない限り、デフォルトでコピーされます:
int main() {
// デフォルトのコピー動作
int x = 10;
int y = x; // コピー(xとy両方が有効)
println("{x} {y}"); // OK: 両方アクセス可能
// 明示的な移動
int a = 20;
int b = move a; // 移動
println("{b}"); // OK
// println("{a}"); // エラー: aは移動済み
return 0;
}
借用(アドレス取得による借用カウント)
重要: Cm v0.11.0では、変数のアドレスを取得(&演算子)すると、その変数は「借用中」として記録されます。
借用の仕組み
int main() {
int x = 100;
int* px = &x; // &演算子でxのアドレスを取得 → xは借用中になる
// 借用中の制限:
// int y = move x; // コンパイルエラー: 借用中は移動不可
// x = 200; // コンパイルエラー: 借用中は変更不可
// x++; // コンパイルエラー: 借用中は変更操作不可
println("*px = {*px}"); // ポインタ経由でのアクセスはOK
return 0;
}
constポインタと通常のポインタ
int main() {
// constポインタ - 参照先を変更できない
const int value = 42;
const int* cptr = &value;
// *cptr = 50; // エラー: constポインタ経由での変更は不可
// 通常のポインタ - 参照先を変更可能
int mutable = 10;
int* ptr = &mutable; // mutableは借用中になる
*ptr = 20; // ポインタ経由での変更はOK(ポインタ自体はconstでない)
// ただし、mutable自体への直接操作は不可:
// mutable = 30; // エラー: 借用中は直接変更不可
// mutable++; // エラー: 借用中は変更操作不可
return 0;
}
現在の制限事項
注意: 現在の実装では以下の制限があります:
- 借用カウントの解放タイミング - スコープ終了時まで借用が維持される(手動解放は未実装)
- 複数借用 - 同一変数への複数ポインタ取得は可能だが、すべてカウントされる
- 関数引数での借用 - 関数にポインタを渡しても借用は追跡されない
void use_pointer(int* p) {
*p = 100;
}
int main() {
int x = 50;
use_pointer(&x); // 関数呼び出し時の借用は追跡されない
x = 60; // これは現在エラーにならない(実装上の制限)
return 0;
}
借用の制限
Cmでは、借用中の変数に以下の制限があります:
- 借用中の変数は移動できない - ポインタが取得された変数はmove不可
- 借用中の変数は変更できない - ポインタで参照中の変数への代入は禁止
- 借用中の変数は変更操作できない - インクリメント等も禁止
次のステップ
✅ 所有権と移動を理解した
✅ 借用(参照)の使い方がわかった
⏭️ 次は ライフタイム を学びましょう
最終更新: 2026-02-08