この記事のポイント

  • 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リクエストヘッダーに存在するかもしれないトークン処理

良い実装例:optionalで状態責務明文化
#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()を即呼びし例外を暗黙依存している例。

optional.value()誤用例
auto token = extractToken(header).value();  // 有無チェックなし
@Reviewer
value()は未定義例外を投げます。事前の有無確認を設計責任として整理してください。

問題点

  • 状態安全性を破壊
  • 設計で型シグネチャ上明文化できていた利点を捨てている

改善例

修正例:有無判定の徹底
auto result = extractToken(header);
if (result) { use(result.value()); }
  • optionalは型上の有無契約
  • 使う側で明示確認が設計原則

良い実装例(string_view)

ユースケース:巨大文字列中の部分ビュー参照

良い実装例: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を保持して寿命破壊している例。

view寿命崩壊例
std::string_view getView() {
    std::string temp = "example";
    return temp;  // UB:一時オブジェクト寿命終了
}
@Reviewer
viewは所有権を持ちません。一時領域参照で寿命が切れます。所有権責任設計が必要です。

問題点

  • 一時所有権の寿命超過
  • UB誘発

改善例

修正例:所有権移譲
std::string getString() { return "example"; }

std::string_view getView(const std::string& source) { return source; }
  • viewは参照元と一体で寿命設計する

良くない実装例: ケース3

次はoptionalで2重に曖昧化している例。

optional<view>混合例
std::optional<std::string_view> extract();
@Reviewer
optionalと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で設計責務整理

UML Diagram

観点チェックリスト

実務レビューFAQ

Q1. optionalはnullable代替?
→ 完全な代替ではない。「有無責任整理」のために導入。

Q2. value()は悪か?
→ 事前有無判定が設計責務。value()裸呼びは原則レビューでNG。

Q3. string_viewは積極採用?
→ 短寿命読み取り用途に限定。長寿命不定時はstring利用。

Q4. optionalはアリ?
→ 分離設計を慎重に行った上で、どうしても必要時のみ。

Q5. viewを返すAPIは安全?
→ 呼出側の寿命責任整理次第。返却時は寿命保証契約必須。

まとめ

optional/viewはC++現代設計における責任整理型である。
レビューアーは

  • optional → 状態有無責任
  • view → 所有権寿命責任

これを設計責任として読み解き、
API契約へ安全に反映させる技術力を磨く必要がある。
レビューアーは型ではなく「契約」をレビューする。