C++変数と定数の使い分け設計レビュー|const-correctness・スコープ設計・変更不能性を読み取るレビュー観点
この記事のポイント
- 「定数化できるか? 変数に残すべきか?」の設計判断をレビューで読み取る力をつける
- const-correctnessをレビュー観点として捉え直す
- スコープ・変更可能性・初期化タイミングを整理する
レビューの現場では「const付けましょう」と形式的に指摘される場面も多いですが、
本来は変更可能性の設計意図を読み取るレビューが重要になります。
1. 変数定義がレビュー対象になる理由
1-1. 変更可能性は設計そのものに関わる
- 誰がいつこの値を変更する想定なのか?
- そもそも本当に変更する必要があるのか?
- 誤って変更されないように守るべきか?
この判断がコードにはっきり表現されていることが大事です。
1-2. 設計意図が埋め込まれていない例
int retryCount = 3;
この 3
は単なる数字ですが、
- 仕様で固定なのか
- 環境で変わる前提なのか
- テストで差し替える想定なのか
レビューアーはこういった背景を読み取る必要があります。
2. 変数定義は「管理責任の宣言」でもある
パターン | 説明 |
---|---|
定数(constexpr / const ) |
変更禁止を明示して固定 |
変更可能変数 | 状態変化の必要がある設計 |
誤変更誘発変数 | 本来固定のはずが変更可能に残してしまった設計 |
3. constexpr と const の使い分け
3-1. constexpr(完全固定)
- コンパイル時に値が確定するもの
- 実行時のコストゼロ
- 設計的にも「動かない設計」を意味する
constexpr int MaxRetryCount = 3;
3-2. const(実行時固定)
- 実行時に決まるけれど、その後変更不可
- 設定ファイル読込結果などに多い
const int RetryLimit = config.GetDefaultRetryLimit();
3-3. 比較表まとめ
| 特性 | constexpr | const | |–|–| | 決定タイミング | コンパイル時 | 実行時含む | | 設計意図 | 完全固定宣言 | 実行後固定宣言 | | 最適化効果 | 高い | 状況次第 |
4. const-correctness というレビューの要所
4-1. const-correctness = 変更不能契約の宣言
class Config {
public:
std::string GetName() const;
};
- メンバ関数に
const
が付いていれば、
「この関数は状態を変更しません」 と読むことができます。
4-2. const を付ける場所は多い
- 関数引数
- 戻り値
- メンバ関数自体
- ポインタ・参照先の内容
void Process(const ApiRequestLog& request);
- const は実装の都合ではなく、設計意図の整理結果として付くもの です。
5. 良い実装例:設計が整理された定義
#pragma once
#include <string>
struct ApiRequestLog {
int requestId;
std::string endpoint;
std::string clientIp;
};
inline constexpr int DefaultTimeoutSeconds = 30;
class Config {
public:
Config(const std::string& filename);
int GetMaxRetryCount() const;
private:
const std::string configFile;
};
- 定数は
constexpr
/const
を使い分けて整理 - 不変メンバには
const
を付け、設計意図を明確にしている
6. よくある誤りとレビュー例
ケース1:本来固定なのに変数にしてしまう
int DefaultTimeoutSeconds = 30;
@Reviewer固定値ならconstexprで定数化してください
改善例
inline constexpr int DefaultTimeoutSeconds = 30;
ケース2:const 漏れ(関数引数)
void Process(ApiRequestLog& request);
@Reviewer参照専用ならconstを付けて意図を明示してください
改善例
void Process(const ApiRequestLog& request);
ケース3:const 漏れ(メンバ関数)
class Config {
public:
int GetMaxRetryCount();
@Reviewer状態変更しない関数はconst指定してください};
改善例
class Config {
public:
int GetMaxRetryCount() const;
};
7. PlantUMLで整理する設計責務
- 定数と可変の責務が分かれて整理されている
- 依存も過剰にならず管理しやすい構造
8. CI統制:変更不能性レビューの支援ツール
clang-tidy 例
Checks: '-*,cppcoreguidelines-avoid-magic-numbers,readability-const-return-type'
- マジックナンバー排除
- const 漏れの指摘
include-what-you-use 活用
- 定数ヘッダーの整理でインクルード最小化も支援できる
PR文化としても統制
- 「constは設計意図を表す」文化をレビュー文化にする
9. レビュー観点チェックリスト
観点 | 確認すること |
---|---|
定数化できるもの | constexpr を積極的に利用しているか |
実行時固定 | const で正しく固定しているか |
マジックナンバー排除 | 裸の数字が散らばっていないか |
const-correctness | 関数・引数・戻り値・メンバのconst漏れ確認 |
スコープ設計 | グローバル/クラス内/関数内で整理できているか |
ODR安全性 | inline constexpr で多翻訳単位の安全性確保 |
CI統制 | 自動チェックで漏れなく検出できているか |
10. まとめ
定数と変数の設計は、実は
「誰がいつ責任を持って値を変更できるのか?」 を整理している作業でもあります。
レビューアーは「constを付けましょう」ではなく
「そもそも誰が管理する値なのか?」
という設計の背景を読み取る視点を持つことがとても重要です。
こうした読み取りができると、自然と保守性も高くなり、設計としても安定します。