この記事のポイント

  • std::arrayをレビューアーがどのように読み解くべきか整理
  • vectorと使い分けるための設計判断基準を解説
  • 固定長配列設計における責務集中レビューを習得

そもそもstd::arrayとは

C++11から導入された std::array固定長安全配列を表現する標準コンテナです。

std::array<int, 10> arr{};

裸配列(raw array)の以下の問題を解消します。

  • サイズ情報の失伝
  • 配列長の静的管理
  • 所有権責務の曖昧さ
  • スコープ自動解放の欠如

std::array固定長でありながら、安全性と所有権集中が得られる という位置づけです。

std::arrayの特徴整理
  • サイズはコンパイル時固定
  • スコープ管理で例外安全が保証される
  • 生配列と違いコピー・代入が可能
  • C配列APIとのブリッジも可能(.data()利用)

レビューアーはvectorとの違いを理解しながら、適切な使用場面を判定する役割を担います。

なぜこれをレビューするのか

固定長配列なのに裸配列を残している実装は依然多く残ります。
以下のような問題が継続します。

  • 境界外アクセスの静的検出困難
  • delete[]責務の分散
  • サイズ長の分散管理
  • 保守性の低下

レビュー段階でstd::array移行を提案することで、固定長構造の安全性が飛躍的に向上します。

レビューアー視点

  • サイズ固定配列の設計意図を読み解く
  • std::array移行可能箇所を洗い出す
  • 所有権責務がスコープに集約されているか確認
  • vectorとの使い分け理由を設計から読み取る

開発者視点

  • 固定長なら常にstd::arrayを第一候補に置く
  • スコープに基づく自動解放設計に寄せる
  • 生配列API境界部だけ裸配列併用
  • vectorとの役割分担を整理

良い実装例

想定:APIリクエストの固定バッファ保持

良い設計例
#include <array>
#include <string>
#include <iostream>

struct ApiRequestLog {
    int requestId;
    std::string endpoint;
    std::string clientIp;
    int responseCode;
    time_t requestedAt;
};

class LogBuffer {
public:
    static constexpr size_t capacity = 10;

    void add(const ApiRequestLog& logEntry, size_t index) {
        if (index >= logs_.size()) {
            throw std::out_of_range("Index out of range");
        }
        logs_[index] = logEntry;
    }

    void dump() const {
        for (const auto& log : logs_) {
            std::cout << log.requestId << std::endl;
        }
    }

private:
    std::array<ApiRequestLog, capacity> logs_;
};

良いポイント

  • サイズ固定をコンパイル時に保証
  • delete[]責務不要
  • 例外安全保証
  • 境界外アクセスを防御可能

レビュー観点

  • 裸配列使用箇所をstd::arrayへ移行できているか
  • サイズ固定意図が設計から読み取れるか
  • delete[]責務が完全排除されているか
  • スコープでライフサイクル集中管理されているか
  • 境界外アクセスが構造防止されているか
  • vectorとの使い分け方針が明示されているか

良くない実装例: ケース1(固定長裸配列維持)

問題例①
void process() {
    ApiRequestLog logs[10];

    logs[0].requestId = 1;
}
@Reviewer
固定長配列はstd::arrayへ移行してください。サイズ管理を型レベルで埋め込み、裸配列による境界外アクセスリスクを排除しましょう。

問題点

  • サイズ管理が外部に分散
  • 型安全性が低い
  • 境界違反検出が困難

改善例

改善例①
std::array<ApiRequestLog, 10> logs{};
logs[0].requestId = 1;

良くない実装例: ケース2(動的確保で固定長を模倣)

問題例②
ApiRequestLog* logs = new ApiRequestLog[10];
logs[0].requestId = 1;
delete[] logs;
@Reviewer
固定長意図ならstd::arrayへ移行してください。動的確保の必要はなく、所有権をスコープ管理で集中できます。

問題点

  • delete[]責務残存
  • 例外安全性欠如
  • 所有権が読み取れない

改善例

改善例②
std::array<ApiRequestLog, 10> logs{};
logs[0].requestId = 1;

良くない実装例: ケース3(API契約に裸配列露出)

問題例③
void save(ApiRequestLog logs[10]) {
    for (size_t i = 0; i < 10; ++i) {
        std::cout << logs[i].requestId << std::endl;
    }
}
@Reviewer
API契約もstd::array受取に変更してください。サイズ管理責務を型レベルに吸収し、呼び出し側の契約負担を軽減しましょう。

改善例

改善例③
void save(const std::array<ApiRequestLog, 10>& logs) {
    for (const auto& entry : logs) {
        std::cout << entry.requestId << std::endl;
    }
}

観点チェックリスト


まとめ

std::arrayレビューは
「裸配列排除+固定長責務集中」 という安全設計レビューです。

レビューアーは常に

  • サイズ固定なら裸配列でなくstd::arrayで設計しているか?
  • 型情報で契約を明示化しているか?
  • delete[]が設計から消滅しているか?

を読み取り、所有権集中+スコープ安全な設計 へ誘導することが重要になります。

UML Diagram