C++レビュー|ヒープとスタックの使い分け基準と設計レビュー観点整理
この記事のポイント
- ヒープとスタックの使い分け設計をレビューアーが読み解く技術を整理
- 寿命責務・所有権・パフォーマンスの設計判断をレビュー視点で解説
- new/delete露出の是非を読み取るレビュー力を養う
そもそもヒープとスタックとは
C++におけるメモリ配置は大きく次の2種類に分類できます。
| 領域 | 特徴 |
|---|---|
| スタック | 自動変数、関数スコープ依存、自動解放、高速、容量制限 |
| ヒープ | new/delete管理、寿命自由、手動解放必要、断片化注意 |
比較ポイント整理
- 寿命:スタックはスコープ従属、ヒープは自由
- 速度:スタックは非常に高速(ポインタ加算のみ)
- 安全性:スタックは自然解放、ヒープは解放漏れリスク
- 容量:ヒープは大容量可能、スタックは上限制約あり
レビューアーは「なぜこの配置選択が採用されたのか?」を静的に読み取ります。
なぜこれをレビューするのか
ヒープ/スタックの使い分けは設計全体の保守性・安全性・パフォーマンスに直結します。
- ヒープ不要な場面でのnew多用 → 解放責務分散
- スタックで巨大オブジェクト確保 → スタックオーバーフロー事故
- 寿命誤読によるuse-after-free発生
レビュー段階で
寿命と所有権を静的に読み解く習慣が最重要です。
レビューアー視点
- 寿命管理をスコープ管理で吸収できるか確認
- ヒープ配置は解放責任が集中しているか確認
- new露出が不要でないか静的に評価
- サイズ・容量をスタック制約に合わせて整理できるか確認
- 例外安全性を構造保証できるか評価
開発者視点
- まずスタック前提で設計を考える
- サイズ超過や寿命要件で必要時のみヒープ選択
- ヒープ採用時はRAIIを前提に責務集中
- コンテナ活用で動的寿命管理を構造吸収
良い実装例
想定:APIリクエストログのスタック集中モデル
良い設計例
#include <string>
#include <iostream>
struct ApiRequestLog {
int requestId;
std::string endpoint;
std::string clientIp;
int responseCode;
time_t requestedAt;
};
void process() {
ApiRequestLog log {
1001, "/api/items", "192.168.0.10", 200, std::time(nullptr)
};
std::cout << log.requestId << std::endl;
}良いポイント
- スタック上の自動変数で寿命管理
- スコープ終了で自動解放
- new/delete完全排除
- 例外安全自然保証
レビュー観点
- newが必要な場面か?(不要new排除)
- スタックサイズ内に収まる設計か
- RAIIによる自動解放構造に寄せられているか
- ヒープ採用時は所有権集中・RAII統合できているか
- API契約に解放責務を転嫁していないか
- 例外発生時にも安全か
良くない実装例: ケース1(不要new使用)
問題例①
void process() {
ApiRequestLog* log = new ApiRequestLog();
log->requestId = 1001;
std::cout << log->requestId << std::endl;
delete log;
}
@Reviewernew/deleteを使用する必要がありません。スタック自動変数で寿命管理してください。RAII構造に統一しましょう。
改善例
改善例①
ApiRequestLog log {1001, "/api/items", "192.168.0.10", 200, std::time(nullptr)};良くない実装例: ケース2(巨大スタック構造)
問題例②
void process() {
char buffer[10 * 1024 * 1024]; // 10MBスタック確保
}
@Reviewerスタック容量超過リスクがあります。巨大バッファはヒープ(std::vector等)管理へ移行してください。
改善例
改善例②
std::vector<char> buffer(10 * 1024 * 1024);良くない実装例: ケース3(寿命管理の分散)
問題例③
class LogSession {
public:
void start() {
log_ = new ApiRequestLog();
}
void end() {
delete log_;
}
private:
ApiRequestLog* log_;
};
@Reviewernew/deleteはRAII構造で集中管理してください。unique_ptr管理に移行しましょう。end()自体が不要になります。
改善例
改善例③
class LogSession {
public:
LogSession() : log_(std::make_unique<ApiRequestLog>()) {}
private:
std::unique_ptr<ApiRequestLog> log_;
};観点チェックリスト
まとめ
ヒープ/スタックレビューは
「寿命責任がスコープに埋め込めるかを読み取るレビュー」です。
レビューアーは常に
- newを使わずに済ませられないか?
- 巨大オブジェクトは安全に管理できているか?
- 解放責務は自然解放構造に吸収されているか?
を静的に読み取り、寿命集中+安全領域設計へ誘導するのが役割です。
