RAII パターン
Resource Acquisition Is Initialization。リソース管理の基本。
概要
RAII(Resource Acquisition Is Initialization)は C++の最重要パターンです。
リソースの取得 = 初期化、 スコープ離脱 = リソース自動破棄
RAII の基本
#include <iostream>
class Resource {
public:
Resource() {
std::cout << "リソース取得" << std::endl;
}
~Resource() {
std::cout << "リソース解放" << std::endl;
}
};
int main() {
{
Resource res; // コンストラクタ: リソース取得
} // デストラクタ: リソース自動解放
std::cout << "完了" << std::endl;
return 0;
}
リソース取得
リソース解放
完了
スコープを抜けれ、自動的にデストラクタが呼ばれます。
ファイル操作での RAII
#include <iostream>
#include <fstream>
void writeFile() {
std::ofstream file("data.txt"); // ファイルを開く(コンストラクタ)
if (file) {
file << "Hello, World!" << std::endl;
file << "C++ RAII" << std::endl;
}
} // ファイルが自動的に閉じられる(デストラクタ)
int main() {
writeFile();
std::cout << "ファイル書き込み完了。自動で閉じられました。" << std::endl;
return 0;
}
ファイル書き込み完了。自動で閉じられました。
手動でclose()を呼ぶ必要がありません。
例外安全性
RAII の大きな利点は例外安全性です。
#include <iostream>
#include <fstream>
void dangerousCode() {
FILE* file = fopen("data.txt", "w");
fprintf(file, "Data");
if (/* エラー */) {
throw std::runtime_error("エラー");
// fclose(file); へ到達しない! メモリリーク!
}
fclose(file);
}
void safeCode() {
std::ofstream file("data.txt"); // RAII で管理
file << "Data";
if (/* エラー */) {
throw std::runtime_error("エラー");
// スコープを抜ける際、自動的に閉じられる。リークしない!
}
}
カスタムリソース管理クラス
#include <iostream>
class Database {
private:
char* connection;
public:
Database(const char* name) {
connection = new char[256];
snprintf(connection, 256, "DB: %s", name);
std::cout << "DB接続: " << connection << std::endl;
}
~Database() {
std::cout << "DB切断: " << connection << std::endl;
delete[] connection;
}
void query(const char* sql) {
std::cout << "実行: " << sql << std::endl;
}
};
int main() {
{
Database db("mydb");
db.query("SELECT * FROM users");
} // 自動的に接続が切られる
std::cout << "完了" << std::endl;
return 0;
}
DB接続: DB: mydb
実行: SELECT * FROM users
DB切断: DB: mydb
完了
スマートポインタも RAII
#include <iostream>
#include <memory>
class Object {
public:
~Object() {
std::cout << "Object 破棄" << std::endl;
}
};
int main() {
{
std::unique_ptr<Object> obj = std::make_unique<Object>();
std::cout << "Object 使用中" << std::endl;
} // スコープ離脱時に自動破棄
std::cout << "完了" << std::endl;
return 0;
}
Object 使用中
Object 破棄
完了
std::unique_ptrは RAII を実装しており、 スコープを抜ける際に自動削除されます。
ポイント
- RAII: リソース取得 = 初期化
- スコープ離脱時に自動破棄
- 例外安全性の向上
- スマートポインタは RAII の実装
まとめ
- RAII は C++の基本設計パターン
- 手動リソース管理を避ける
- スマートポインタとカスタムクラスで実装