C++の=default, =delete構文は設計意図をコードに埋め込む|レビューで正しく理由付けされた適用を確認する技法
この記事のポイント
- =default, =deleteの役割と設計意図を整理
- レビューで自動生成制御が適切かどうかを確認する技法を解説
- 実務コード改善例・レビュー観点を提示
C++11で導入された設計明示記法
C++11から以下が導入されました。
構文 | 役割 |
---|---|
=default |
自動生成明示許可 |
=delete |
生成禁止明示 |
本質は「意図をコードに埋め込む設計言語」
- 暗黙生成の黙認設計を防止
- 明示設計文化の中核機能
なぜレビュー対象になるのか
① 自動生成任せが設計責務を曖昧化する
- 誰がどの設計意図でコピー・代入・moveを許可したか読めない
② 意図不一致事故を事前封止できる
- 型安全破壊を事前に排除
③ 保守時の安全性を高める
- 拡張追加で自動生成が暴走するのを防止
④ 設計の責務をレビュー時に可視化できる
- 実質ドキュメントとして機能
良い実装例
class FileHandle {
public:
explicit FileHandle(int fd) : fd_(fd) {}
FileHandle(const FileHandle&) = delete; // コピー禁止
FileHandle& operator=(const FileHandle&) = delete; // 代入禁止
FileHandle(FileHandle&&) noexcept = default; // ムーブ許可
FileHandle& operator=(FileHandle&&) noexcept = default;
private:
int fd_;
};
良い設計理由
- 所有権一意性を完全保証
- ムーブ転送は安全許可
- レビュー対象が意図読み取り可能
レビュー観点
レビューアーは以下を確認する。
- コピー・代入の許可/禁止が責務設計と一致しているか
=default
使用は理由付けされているか=delete
はコピー側・代入側とも適用されているか- C++03残存のprivateコピー禁止記法が混在していないか
- ムーブ専用化設計はconsistentに統一されているか
良くない実装例: ケース1
class Resource {
public:
Resource() = default;
};
@Reviewerデフォルト生成理由が説明されていません。意図が不明瞭です。
改善例
// 非所有型でデフォルト生成許可設計
class Resource {
public:
Resource() = default;
};
ケース2: コピー片側だけ禁止
class Connection {
public:
Connection(const Connection&) = delete;
};
@Reviewerコピー代入演算子も禁止してください。不整合設計です。
改善例
Connection& operator=(const Connection&) = delete;
ケース3: ムーブ専用意図の記述抜け
class Socket {
public:
explicit Socket(int fd);
Socket(Socket&&) noexcept = default;
};
@Reviewerムーブ設計時もコピー禁止は必ず明示してください。
改善例
Socket(const Socket&) = delete;
Socket& operator=(const Socket&) = delete;
ケース4: delete理由の可視化欠落
class Logger {
public:
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
};
@Reviewerdelete理由(設計責務)をコメントで補足してください。
改善例
// シングルトン設計のためコピー禁止
class Logger {
public:
Logger(const Logger&) = delete;
Logger& operator=(const Logger&) = delete;
};
ケース5: C++03流残存
class FileHandle {
private:
FileHandle(const FileHandle&);
FileHandle& operator=(const FileHandle&);
};
@ReviewerC++11以降はdelete指定に統一してください。意図がより明示的です。
改善例
class FileHandle {
public:
FileHandle(const FileHandle&) = delete;
FileHandle& operator=(const FileHandle&) = delete;
};
ケース6: default使わずわざわざ空実装
class Task {
public:
Task() {}
};
@Reviewer空実装でなく=default使用で意図明示してください。
改善例
class Task {
public:
Task() = default;
};
「書かずに済むから使わない」ではなく、設計をコード化する意識
default/deleteレビューの設計防止効果
設計崩壊 | default/deleteで防止できる理由 |
---|---|
コピー責務曖昧化 | コピー禁止明示 |
デフォルト生成暴走 | 意図的許可のみ許容 |
ムーブ安全性未保証 | move専用許可設計 |
保守バグ温床化 | 拡張時の暴走制御 |
観点チェックリスト
まとめ
レビューアーが常に確認すべき判断基準はこれです:
「特殊メンバ生成は設計意図を反映して明示されているか?」
- default/deleteは設計意図の自己文書化構文
- C++レビューの標準作法として完全明示文化を定着させる
「暗黙生成撲滅文化」こそ現代C++レビュー力の核心です。