C++のメンバー初期化リストは漏れなく活用する|レビューでコンストラクタ初期化の安全性と責務一貫性を確認する技法
この記事のポイント
- メンバー初期化リストの原則と漏れやすい危険性を整理
- レビューで安全性・性能・責務意図を確認する具体技法を解説
- 実務コードの改善例・レビュー観点を提示
C++におけるメンバー初期化リストの役割
C++ではコンストラクタ内でメンバーを次の2通りで初期化可能です。
初期化方法 | 記法 | 説明 |
---|---|---|
メンバー初期化リスト | : member(value) |
正統派 |
コンストラクタ本体代入 | { member = value; } |
代入 |
レビューで重要なのは以下
初期化は初期化リストで行うのが設計の基本である
なぜレビュー対象になるのか
① 値の二重代入が発生しやすい
- 代入式はデフォルト初期化 → 再代入の冗長
② constメンバーが代入不能
- 初期化リスト以外では代入できない
③ 参照型メンバーも初期化リスト必須
④ 順序依存の事故が起きやすい
- メンバー定義順に依存する初期化
⑤ 保守時に意図読み取り負荷が上昇
- メンバー初期化状態が散在
初期化リストの原則
メンバー種別 | レビュー判断 |
---|---|
値型 | 初期化リスト推奨 |
const | 必須 |
参照型 | 必須 |
ポインタ型 | 原則推奨(明示性維持) |
良い実装例
class User {
public:
User(int id, const std::string& name)
: id_(id), name_(name) {}
private:
int id_;
std::string name_;
};
良い設計理由
- 一貫して初期化リスト使用
- const安全性保証
- 意図読み取り容易
レビュー観点
レビューアーは以下を確認する。
- 全メンバーが初期化リストで初期化されているか
- const・参照型は必ず初期化リスト使用されているか
- デフォルト→代入の冗長処理が残存していないか
- 初期化順序に潜在事故が含まれていないか
- 初期化責務がコンストラクタ本体に漏れていないか
良くない実装例: ケース1
class User {
public:
User(int id, const std::string& name) {
id_ = id;
name_ = name;
}
private:
int id_;
std::string name_;
};
@Reviewer初期化リストを使用してください。無駄な二重代入が発生しています。
改善例
User(int id, const std::string& name)
: id_(id), name_(name) {}
ケース2: constメンバーに代入式適用
class Config {
public:
Config(int timeout) {
timeout_ = timeout;
}
private:
const int timeout_;
};
@Reviewerconstメンバーは初期化リスト必須です。代入は成立しません。
改善例
Config(int timeout)
: timeout_(timeout) {}
ケース3: 参照型の初期化漏れ
class Manager {
public:
Manager(Database& db) {
db_ = db;
}
private:
Database& db_;
};
@Reviewer参照型は初期化リストが必須です。代入は無効です。
改善例
Manager(Database& db)
: db_(db) {}
ケース4: 定義順と異なる初期化順序
class Pair {
public:
Pair(int a, int b)
: second(b), first(a) {}
private:
int first;
int second;
};
@Reviewer初期化順序は定義順に従います。順序誤解を防ぐため記述順を揃えてください。
改善例
Pair(int a, int b)
: first(a), second(b) {}
ケース5: defaultメンバ初期化逃避
class User {
public:
User(int id) : id_(id) {}
private:
int id_;
std::string name_ = "unknown";
};
@Reviewerdefault member initializerはコンストラクタ全体設計の整合性をレビュー確認してください。
改善例
User(int id, const std::string& name = "unknown")
: id_(id), name_(name) {}
ケース6: メンバー初期化の責務散在
class Session {
public:
Session() {}
void init(int id, const std::string& token) {
id_ = id;
token_ = token;
}
private:
int id_;
std::string token_;
};
@Reviewer初期化責務はコンストラクタ集中設計を推奨します。
改善例
Session(int id, const std::string& token)
: id_(id), token_(token) {}
メンバー初期化リストレビューの設計意義
防止対象 | 設計効果 |
---|---|
二重代入 | 初期化効率最適化 |
const初期化漏れ | 型安全性維持 |
参照初期化漏れ | コンパイル保証 |
順序誤読 | 初期化整合性可視化 |
責務散在 | 設計集中管理 |
観点チェックリスト
まとめ
レビューアーが常に確認すべき判断基準は:
「本当に初期化リストに集約できているか?」
- 初期化は代入ではない
- 初期化リスト文化が型安全設計文化の中核
「責務集中型初期化レビュー」こそC++レビュー育成の基本スキルです。