C++レビュー|裸配列利用の最小化と安全設計レビュー観点整理
この記事のポイント
- 裸配列(raw array)をレビューアーがどのように読み解くべきか整理
- vector移行を含めた裸配列使用最小化指針を整理
- 安全設計を実現する所有権集中と責務整理レビューができる
そもそも裸配列とは
C++における裸配列(raw array)は以下のような形式です。
int arr[10]; // 固定長ローカル配列
int* arr = new int[10]; // 動的確保配列
C++では長年、この裸配列が一般的に使われてきました。
しかし、以下の特徴から設計上の負債になりやすいです。
- 境界管理が呼び出し側責任
- delete[]忘れリスク
- 例外安全性崩壊
- 所有権責務が曖昧化
C++11以降のモダンC++設計では裸配列の利用は極力最小限に抑えるのが設計標準です。
現代C++の裸配列原則
- std::vectorまたはstd::arrayへ置き換え可能なら置き換える
- 低レベルAPIとの境界以外で裸配列は原則使用しない
- 裸配列使用時は必ず責務集中構造で管理する
レビューアーは裸配列が残存していないか確認し、不要な場合は排除提案する役割を担います。
なぜこれをレビューするのか
裸配列は以下の設計事故を頻発させます。
- 配列長の分散管理
- 境界外アクセスの静的検出困難
- delete[]忘れや二重delete
- 例外安全性の破壊
- API契約の読解困難化
レビューアーはコードの長期保守性・安全性の観点から構造的排除を誘導する必要があります。
レビューアー視点
- どの裸配列が標準コンテナ移行可能かを判定
- 動的確保配列を静的管理構造へ移行提案
- 所有権移譲の明示化を促進
- API契約における配列責務整理を確認
開発者視点
- new/delete[]排除を前提に設計する
- vector/std::array適用箇所を最大化する
- ポインタ+サイズ契約をvector契約に変換する
- 裸配列使用箇所は極小限定(C-API境界等)
良い実装例
想定:APIリクエストログ管理を裸配列最小化
良い設計例
#include <vector>
#include <string>
#include <iostream>
struct ApiRequestLog {
int requestId;
std::string endpoint;
std::string clientIp;
int responseCode;
time_t requestedAt;
};
class LogBuffer {
public:
explicit LogBuffer(size_t capacity)
: logs_(capacity) {}
void add(const ApiRequestLog& logEntry) {
logs_.push_back(logEntry);
}
void dump() const {
for (const auto& log : logs_) {
std::cout << log.requestId << std::endl;
}
}
private:
std::vector<ApiRequestLog> logs_;
};
良いポイント
- 完全に裸配列排除
- delete[]責務消滅
- 境界外アクセス保護
- 例外安全性自然保証
レビュー観点
- 配列利用箇所でvector移行可能箇所が残っていないか
- 動的確保配列をnew/delete[]から隔離しているか
- API契約も裸配列依存を排除できているか
- スコープ管理構造でライフサイクル責務を閉じ込めているか
- 例外安全が構造保証できているか
良くない実装例: ケース1(固定長裸配列)
問題例①
void process() {
ApiRequestLog logs[10];
logs[0].requestId = 1;
}
@Reviewer固定長配列はstd::vectorまたはstd::arrayへ移行してください。サイズ管理責務をコードから排除し、より安全なスコープ管理構造に寄せましょう。
問題点
- サイズ管理が暗黙的
- 拡張性がない
- 境界違反が静的検出困難
改善例
改善例①
std::vector<ApiRequestLog> logs;
logs.push_back({1, "/api/items", "127.0.0.1", 200, std::time(nullptr)});
良くない実装例: ケース2(動的裸配列)
問題例②
ApiRequestLog* logs = new ApiRequestLog[10];
logs[0].requestId = 1;
delete[] logs;
@Reviewernew/delete[]を排除し、vector移行してください。例外安全性・ライフサイクル集中管理が保証されます。
問題点
- delete[]忘れリスク
- 例外時リーク
- 呼び出し側に所有権転嫁
改善例
改善例②
std::vector<ApiRequestLog> logs(10);
logs[0].requestId = 1;
良くない実装例: ケース3(API契約裸配列露出)
問題例③
void save(ApiRequestLog* logs, size_t count) {
for (size_t i = 0; i < count; ++i) {
std::cout << logs[i].requestId << std::endl;
}
}
@ReviewerAPI契約もvector受取にリファクタリングしてください。裸配列+サイズ契約は分散責務となり、vectorなら一括管理可能です。
改善例
改善例③
void save(const std::vector<ApiRequestLog>& logs) {
for (const auto& entry : logs) {
std::cout << entry.requestId << std::endl;
}
}
観点チェックリスト
まとめ
裸配列レビューは
「責務分散を責務集中に読み替える作業」です。
レビューアーは
- まだ残っている裸配列はどこか?
- スマートポインタ・vector移行は可能か?
- API契約まで移行できる構造か?
を常に読み解き、設計全体の安全領域へ押し上げる判断力が必要になります。