C++レビュー|new/delete箇所の集中管理と安全設計レビュー観点整理
この記事のポイント
- new/delete使用箇所の集中管理設計をレビューアーが読み解く技術を整理
 - 解放責務の分散排除と所有権明示のレビュー観点を整理
 - スマートポインタ移行とRAII設計徹底のレビュー技術を解説
 
そもそもnew/delete集中管理とは
C++におけるnew/deleteは動的メモリ管理の最低レイヤです。
極めて柔軟ですが、以下のリスクを常に孕んでいます。
- 解放漏れ(メモリリーク)
 - 二重delete(未定義動作)
 - 例外発生時の途中解放不能
 
設計の基本は
「new/deleteの露出を可能な限り狭いスコープに集中させる」
ことにあります。
集中管理の基本原則
- new/deleteはコンストラクタ+デストラクタ内限定が基本形
 - 呼び出し側へ解放責任を転嫁しない
 - RAII徹底による自動解放に寄せる
 - 可能な限りスマートポインタ・標準コンテナに吸収
 
レビューアーはnew/delete露出箇所を読み取り、集中管理領域へ寄せ切れているか確認する役割を持ちます。
なぜこれをレビューするのか
new/deleteがコード全体に散乱すると以下の設計崩壊を誘発します。
- メモリ解放責務が分散 → 管理不能化
 - 例外発生時リーク → 安全性破綻
 - テスト容易性低下
 - 読解コスト肥大化
 
レビュー段階で
「new/deleteがどこに現れているか」
を静的に全スコープで読み切る力がレビューアーの品質を左右します。
レビューアー視点
- new箇所を完全に洗い出す
 - delete箇所が複数箇所に存在していないか確認
 - スマートポインタ移行可能性を確認
 - コンストラクタ集中に設計寄せできているか確認
 - 例外安全性を崩していないか評価
 
開発者視点
- new/deleteは設計責務封じ込めの最上位に置く
 - スマートポインタ・コンテナへ極力移行
 - 解放責任はスコープ管理に寄せる
 - 例外安全性を自然保証できる構造に設計する
 
良い実装例
想定:APIリクエストログの集中管理型
良い設計例
#include <memory>
#include <vector>
#include <string>
#include <iostream>
struct ApiRequestLog {
    int requestId;
    std::string endpoint;
    std::string clientIp;
    int responseCode;
    time_t requestedAt;
};
class LogBuffer {
public:
    void add(std::unique_ptr<ApiRequestLog> logEntry) {
        logs_.push_back(std::move(logEntry));
    }
    void dump() const {
        for (const auto& entry : logs_) {
            std::cout << entry->requestId << std::endl;
        }
    }
private:
    std::vector<std::unique_ptr<ApiRequestLog>> logs_;
};
void process() {
    auto log = std::make_unique<ApiRequestLog>();
    log->requestId = 123;
    LogBuffer buffer;
    buffer.add(std::move(log));
}良いポイント
- new/delete完全封じ込み
 - 寿命責務集中
 - 例外安全自然保証
 - API契約明示化(所有権移譲)
 
レビュー観点
- new呼び出し箇所を完全把握できるか
 - deleteが複数箇所に分散していないか
 - コンストラクタ集中に設計寄せできているか
 - スマートポインタ移行余地が残っていないか
 - 呼び出し側の解放責務が消滅しているか
 - 例外時も寿命保証されているか
 
良くない実装例: ケース1(delete責務分散)
問題例①
class LogBuffer {
public:
    void add(ApiRequestLog* logEntry) {
        logs_.push_back(logEntry);
    }
    void cleanup() {
        for (auto* entry : logs_) {
            delete entry;
        }
        logs_.clear();
    }
private:
    std::vector<ApiRequestLog*> logs_;
};
@Reviewerdelete責務がクラス内に分散しています。スマートポインタを導入し、所有権移譲をadd()引数型で明示してください。cleanup()も不要になります。
問題点
- 解放責務分散
 - 保守コスト上昇
 - 例外時安全性不保証
 
改善例
改善例①
void add(std::unique_ptr<ApiRequestLog> logEntry) {
    logs_.push_back(std::move(logEntry));
}良くない実装例: ケース2(コンストラクタ集中欠如)
問題例②
class Session {
public:
    void start() {
        log_ = new ApiRequestLog();
    }
    void end() {
        delete log_;
    }
private:
    ApiRequestLog* log_;
};
@Reviewernew/deleteはコンストラクタとデストラクタに集中させてください。可能ならunique_ptr導入で自動解放に統合してください。
改善例
改善例②
class Session {
public:
    Session() : log_(std::make_unique<ApiRequestLog>()) {}
private:
    std::unique_ptr<ApiRequestLog> log_;
};良くない実装例: ケース3(スマートポインタ未導入)
問題例③
ApiRequestLog* log = new ApiRequestLog();
// 処理略
delete log;
@Reviewernew/deleteは基本的にコード露出を排除してください。スマートポインタまたはスコープ自動管理構造に統一移行してください。
改善例
改善例③
auto log = std::make_unique<ApiRequestLog>();観点チェックリスト
まとめ
new/delete集中管理レビューは
「破棄責任を構造上読める設計に仕上げるレビュー」です。
レビューアーは常に
- new呼び出しはどこに存在するか?
 - delete責務は集中管理されているか?
 - 自動解放設計に寄せ切れているか?
 
を静的に読み取り、RAII徹底 → 呼び出し側負荷ゼロ化設計へ誘導するのが役割です。
