C++レビュー|static・グローバル変数の使い方で設計崩壊を防ぐレビュー技術
この記事のポイント
- static・グローバル変数使用が設計崩壊に繋がる理由を理解する
- レビューで責務境界の歪みを早期に検出する力を養う
- 静的初期化順序や並列競合など実務上の危険信号を整理する
グローバル変数・static変数は
「便利さの裏にある設計負債の温床」 です。
レビューアーは「使用しているか否か」ではなく
スコープ設計と責務の整理具合 を読み取る必要があります。
1. そもそもstatic変数・グローバル変数とは?
1-1. グローバル変数
int GlobalCounter = 0;
- 全翻訳単位から自由にアクセス可能
- プログラム中ずっと存在する共有状態
- 誰がいつ変更するか曖昧になりやすい
1-2. static変数
ファイルスコープ static(内部リンケージ)
static int FileLocalCounter = 0;
- 定義したソースファイル内のみ有効
- 他ファイルからは参照不能
関数スコープ static
void func() {
static int callCount = 0;
}
- 関数が呼ばれ続ける間、状態を保持し続ける
- 初回呼び出し時に初期化される
2. レビューで確認すべき「危険信号」
2-1. スコープが不必要に広がる
- 影響範囲が不明瞭になる
- 変更影響範囲を追えなくなる
2-2. 初期化順序に依存する
- 静的初期化順序問題(Static Initialization Order Fiasco)
- 複数グローバル間で依存関係が崩れやすい
2-3. 並列競合が潜在する
- スレッド間で同時更新されると破綻
- 並列安全性の考慮が必要
3. レビューアーが重点確認すべき観点
観点 | 確認内容 |
---|---|
スコープの適切さ | 本当にその範囲で共有する必要があるか? |
初期化依存 | 他のstaticに依存していないか? |
責務分離 | 状態保持責任が整理されているか? |
並列安全性 | スレッドセーフか?競合の危険はないか? |
可視性制御 | 内部リンケージで閉じ込められているか? |
4. 良い実装例:インスタンス責務に閉じる設計
#pragma once
#include <string>
class ApiRequestStatistics {
public:
void incrementSuccess() { ++successCount; }
void incrementFailure() { ++failureCount; }
std::string summary() const;
private:
int successCount = 0;
int failureCount = 0;
};
- インスタンスごとの状態で分離
- グローバル共有を回避
- テストや保守が容易
5. 良くない実装例:レビュー指摘パターン
ケース1:無制限グローバル変数
int GlobalRequestCount = 0;
@Reviewerグローバル変数は避けてください。責務を持つクラス側に状態を移動しましょう。
- どのコードでも自由に変更可能
- 変更履歴や影響範囲が追えなくなる
ケース2:静的初期化順序依存の危険
#include <string>
class Logger;
extern Logger GlobalLogger;
class Config {
public:
Config() {
GlobalLogger.log("Config initialized");
}
};
@Reviewerstatic初期化順序依存が発生しています。GlobalLoggerが先に初期化されている保証がありません。
- 順序バグがプラットフォーム依存で発現しやすい
ケース3:関数内staticの無自覚な状態保持
int getGlobalCounter() {
static int counter = 0;
return ++counter;
}
@Reviewer関数内staticで状態保持すると責務が不明確になります。専用の状態管理クラスを切り出しましょう。
6. 改善パターン:責務分離と状態管理の設計
#pragma once
class RequestCounter {
public:
void increment() { ++counter; }
int current() const { return counter; }
private:
int counter = 0;
};
- 状態保持は専用クラスへ隔離
- グローバル依存を完全排除
- 並列化・テスト時も安全性確保しやすい
7. PlantUMLで整理する責務の切り分け
8. CI統制と自動検出の工夫
clang-tidyを活用
Checks: '-*,cppcoreguidelines-avoid-non-const-global-variables'
- グローバル変数混入を静的解析で検出
PRレビュー文化として浸透させる
- 状態保持は専用クラスへ寄せる文化を定着
9. チェックリスト
項目 | チェック内容 |
---|---|
グローバル禁止 | 共有状態を不用意に広げていないか |
static活用 | 内部リンケージで責務内に留められているか |
初期化順序 | 順序依存バグを回避できているか |
責務整理 | 状態保持クラスが存在するか |
並列考慮 | スレッド間競合を防げているか |
CI支援 | 静的解析で検出ルールが整備されているか |
10. まとめ
グローバル変数・static変数レビューは「状態責務の境界線」を読む訓練になる。
- 状態は誰が管理するべきか?
- どの範囲まで見える必要があるか?
- 変更影響を局所化できるか?
レビューアーは「影響範囲の広さ」に常に注意を向けると、設計読み取り力が自然に育っていきます。