C++レビュー|std::optional・std::string_view活用の設計妥当性レビュー整理
この記事のポイント
- optional/viewの利用意図をレビューアー視点で整理
- null許容・所有権・有効期間設計責任を具体的に読み解く
- API契約や安全性まで含めたレビュー観点を体系化
そもそもoptional/viewとは
std::optional
- 値を持つ/持たない状態を明示的に表現可能にする型
T型の値が入る or 空- nullポインタ依存を排除し、状態存在性を型システムに反映
std::optional<int> value = 10;
if (value) { use(value.value()); }std::string_view(view系)
- 参照のみを保持する軽量な読み取りビュー型
- 実体データの所有はしない
- 生ポインタの型安全ラッパー
void process(std::string_view sv) { ... }- optionalはnull安全責務整理
- viewは所有権責務整理
なぜこれをレビューするのか
レビューアー視点
optional/viewの採用は以下の設計責務整理を伴う。
-
状態許容責任の明文化
→ optional適用が意味のある「不在許容」設計になっているか -
所有権管理責任の明文化
→ view使用時に有効期間設計が整理されているか -
API契約の安全性保証
→ 呼出側に伝えるべき責任が契約上明文化されているか -
例外安全設計への影響確認
→ deref時例外 vs null-check責任整理 -
冗長/過剰適用を排除
→ 無意味optional/view濫用抑止
開発者視点
- optionalをnullable代替で乱用
- string_viewを生寿命短い一時領域参照に使い未定義動作
- optional.value()を平然と呼び出し例外化
- view経由で所有権設計を曖昧化
- optional
という2重曖昧型を安易に採用
レビューアーはこれら「責任混同設計」を読み解き、設計修正へ導く役割を持つ。
良い実装例
ユースケース:APIリクエストヘッダーに存在するかもしれないトークン処理
#include <optional>
#include <string>
class AuthHeaderParser {
public:
std::optional<std::string> extractToken(const std::string& header) const {
if (header.starts_with("Bearer ")) {
return header.substr(7);
}
return std::nullopt;
}
};- トークン存在有無がoptionalで明文化
- nullではなく「存在有無」を型責務で整理
- API契約側で呼出時null-check責任分離可能
レビュー観点
- optionalは「本来optionalであるべき設計」か
- 無意味nullable代替になっていないか
- 呼出契約でoptional使用有無が明文化されているか
- deref前の有無確認設計が行われているか
良くない実装例: ケース1
以下はoptional.value()を即呼びし例外を暗黙依存している例。
auto token = extractToken(header).value(); // 有無チェックなし
@Reviewervalue()は未定義例外を投げます。事前の有無確認を設計責任として整理してください。
問題点
- 状態安全性を破壊
- 設計で型シグネチャ上明文化できていた利点を捨てている
改善例
auto result = extractToken(header);
if (result) { use(result.value()); }- optionalは型上の有無契約
- 使う側で明示確認が設計原則
良い実装例(string_view)
ユースケース:巨大文字列中の部分ビュー参照
#include <string>
#include <string_view>
class QueryParser {
public:
QueryParser(std::string_view query) : query_(query) {}
std::string_view getParamSection() const {
auto pos = query_.find('?');
return (pos != std::string_view::npos) ? query_.substr(pos + 1) : std::string_view{};
}
private:
std::string_view query_;
};- コピー発生なし
- 所有権責任が設計上限定されている
- 呼出側寿命保証契約がレビュー可能
レビュー観点
- viewの寿命管理がAPI契約で明文化されているか
- 実体データの所有権責務が曖昧化していないか
- 非const実体との結合時の寿命違反可能性をレビューしているか
- view自体に所有権が無いことを前提設計しているか
良くない実装例: ケース2
以下は一時文字列生成後にviewを保持して寿命破壊している例。
std::string_view getView() {
std::string temp = "example";
return temp; // UB:一時オブジェクト寿命終了
}
@Reviewerviewは所有権を持ちません。一時領域参照で寿命が切れます。所有権責任設計が必要です。
問題点
- 一時所有権の寿命超過
- UB誘発
改善例
std::string getString() { return "example"; }
std::string_view getView(const std::string& source) { return source; }- viewは参照元と一体で寿命設計する
良くない実装例: ケース3
次はoptional
std::optional<std::string_view> extract();
@Revieweroptionalとviewは責務レイヤが異なります。責務分離設計が必要です。
問題点
- 有無責任と寿命責任を二重に混在
- 呼出側の責務負担過剰
改善例
- optional<string> → 有無保証(短寿命ならstring_view可)- string_view → 所有権不保持・有無は呼出契約側で設計API契約パターン整理
optional利用責任設計
| 状態有無 | optional利用可否 |
|---|---|
| 状態常在 | optional不要 |
| 状態非保証 | optional必須 |
view利用責任設計
| 所有権管理 | view利用可否 |
|---|---|
| 呼出側寿命保証可能 | view可 |
| 呼出側寿命保証困難 | 所有型優先 |
optional/view vs pointer設計責任比較
| 型 | 責務特徴 | 推奨適用領域 |
|---|---|---|
| raw pointer | 所有権不明・寿命曖昧 | 低水準内部 |
| unique_ptr | 所有権単一明示 | リソース所有設計 |
| shared_ptr | 参照カウント所有 | 複数共有所有設計 |
| optional | 状態有無責任明示 | nullable設計代替 |
| string_view | 非所有軽量参照 | 短寿命読み取り設計 |
- optional/viewは「存在性責務」と「所有権責務」整理の道具
PlantUMLで設計責務整理
観点チェックリスト
実務レビューFAQ
Q1. optionalはnullable代替?
→ 完全な代替ではない。「有無責任整理」のために導入。
Q2. value()は悪か?
→ 事前有無判定が設計責務。value()裸呼びは原則レビューでNG。
Q3. string_viewは積極採用?
→ 短寿命読み取り用途に限定。長寿命不定時はstring利用。
Q4. optional
→ 分離設計を慎重に行った上で、どうしても必要時のみ。
Q5. viewを返すAPIは安全?
→ 呼出側の寿命責任整理次第。返却時は寿命保証契約必須。
まとめ
optional/viewはC++現代設計における責任整理型である。
レビューアーは
- optional → 状態有無責任
- view → 所有権寿命責任
これを設計責任として読み解き、
API契約へ安全に反映させる技術力を磨く必要がある。
レビューアーは型ではなく「契約」をレビューする。
