RAII
Resource Acquisition Is Initialization
RAII は一般的に 「アールエーアイアイ」 とアルファベットそのままの発音で読むことが多いです。GPT-4.icon
ただし、英語圏の開発者の間では 「ライ」(/ˈraɪ/)と発音されることもあります。
GPT-4.icon
RAII(Resource Acquisition Is Initialization、リソースの獲得は初期化) とは、オブジェクトのライフタイムとリソース管理を結びつける設計原則です。
C++ や Rust などの言語で使われる重要なパターンで、リソース(メモリ、ファイルハンドル、ロックなど)をオブジェクトのコンストラクタで獲得し、デストラクタで解放する ことで、リソースリークを防ぎます。
RAIIの基本的な考え方
オブジェクトがスコープに入るとリソースを確保
オブジェクトがスコープを抜けるとリソースを自動解放
明示的なリソース管理 (new / delete) を不要にし、メモリリークやダングリングポインタのリスクを低減
RAIIの具体例
C++のRAII(スマートポインタ)
普通のポインタ(RAIIなし、メモリリークのリスクあり)
code:cpp
void foo() {
int* p = new int(42); // 明示的にメモリ確保
std::cout << *p << std::endl;
delete p; // 明示的に解放しないとメモリリーク
}
このコードでは、delete を忘れるとメモリリークが発生する可能性があります。
スマートポインタ(RAIIを利用)
code:cpp
void foo() {
std::unique_ptr<int> p = std::make_unique<int>(42); // RAIIを適用
std::cout << *p << std::endl;
} // スコープを抜けると p のデストラクタが自動的に delete を呼ぶ
RAII を適用すると、スコープを抜けた時点で自動的にリソースが解放されるため、delete を呼ぶ必要がなくなります。
RustのRAII
Rust の Box<T> は RAII を利用しており、スコープを抜けると自動的にメモリが解放されます。
ファイルハンドルのRAII
Rust では std::fs::File も RAII を活用しており、スコープを抜けると自動的にクローズされます。
code:rust
use std::fs::File;
fn main() {
let file = File::open("example.txt").unwrap();
// スコープを抜けると file が自動的に閉じられる
}
RAIIの適用範囲
RAII は メモリ管理以外 にも適用され、C++ や Rust の標準ライブラリには RAII に基づくクラスや型が数多く存在します。
table:table
リソースの種類 C++のRAIIクラス RustのRAII型
メモリ管理 std::unique_ptr /std::shared_ptr Box<T> /Rc<T> /Arc<T>
ファイル管理 std::ifstream /std::ofstream std::fs::File
スレッド管理 std::thread std::thread::spawn
ロック管理 std::lock_guard /std::unique_lock std::sync::Mutex
ソケット管理 boost::asio::socket std::net::TcpStream