【C++17】std::optional の使い方 | 値が存在しない可能性を表現する方法

目次

はじめに

C++で、関数が処理に成功した場合は値を返し、失敗した場合は「値がない」ことを示したい、という場面は頻繁にあります。従来は、-1のような特別な値(番兵)を返したり、ポインタでnullptrを返したり、boolの成否フラグを別途返したり、といった方法が取られていましたが、いずれも一長一短でした。

C++17では、この問題を解決する、よりモダンで型安全な方法として std::optional が導入されました。optionalは、

  • 有効な値
  • 値がないことを示す特殊な状態 std::nullopt

のどちらか一方を保持します。これにより、「値が存在しない可能性」を、戻り値の型そのものに明確に表現できます。


【前提】C++17とは?

C++17は、2017年に正式化されたC++言語の規格です。std::optional はこのC++17で追加された機能のため、利用するにはC++17に対応したコンパイラが必要です。


std::optional を使ったサンプルコード

このコードは、文字列を整数に変換する関数 safe_stoi を定義します。変換に成功すればint型の値を持つoptionalを、失敗すれば値がない状態 (nullopt) のoptionalを返します。

完成コード

#include <iostream>
#include <optional>  // optional, nullopt
#include <string>
#include <charconv>  // from_chars

using namespace std;

// 文字列を整数に変換する関数
// 戻り値: 成功ならoptional<int>, 失敗ならnullopt
optional<int> safe_stoi(const string& s) {
    int result;
    auto [ptr, ec] = from_chars(s.data(), s.data() + s.size(), result);

    if (ec == errc()) {
        // 1. 成功した場合: 値を返す
        return result;
    } else {
        // 2. 失敗した場合: std::nulloptを返す
        return nullopt;
    }
}

int main() {
    // --- 成功するケース ---
    optional<int> res1 = safe_stoi("123");
    
    // 3. bool値として評価し、値を持っているかチェック
    if (res1) {
        // 4. .value()または*で値にアクセス
        cout << "成功1: " << res1.value() << endl;
        cout << "成功1 (アスタリスク): " << *res1 << endl;
    }

    // --- 失敗するケース ---
    optional<int> res2 = safe_stoi("abc");

    if (!res2) {
        cout << "失敗2: 変換に失敗しました。" << endl;
    }
    
    // 5. .value_or()で、値がない場合のデフォルト値を提供
    cout << "失敗2 (.value_or): " << res2.value_or(0) << endl;
    
    return 0;
}

コードの解説

1. optional<int> safe_stoi(...)

関数の戻り値の型を std::optional<int> と定義しています。これは、「この関数は、int型の値を返すかもしれないし、返さないかもしれない」という意味になります。

2. return result; / return nullopt;

  • 成功時: return result; のように、有効な値を直接返します。optionalオブジェクトが暗黙的に構築されます。
  • 失敗時: std::nullopt という特別な定数を返します。これにより、このoptionalが「値がない」状態であることが示されます。

3. if (res1)

optionalオブジェクトは、if文などの条件式に置くと、有効な値を持っているかどうかをbool値で評価できます。

  • 有効な値を持っている場合 → true
  • 値がない (nullopt) 場合 → false

4. .value()*

optionalが有効な値を持っている場合に、その値にアクセスするには、.value()メンバ関数か、ポインタのようにアスタリスク*を使います。もし値がないオブジェクトに対してこれらを使うと、例外がスローされます。

5. .value_or(デフォルト値)

optionalが有効な値を持っていればその値を、持っていなければ引数で指定されたデフォルト値を返します。例外を投げないため、if文なしで安全に値を取り出したい場合に便利です。


まとめ

今回は、C++17のstd::optionalを使って、値が存在しない可能性を型安全に表現する方法を解説しました。

  • std::optional<T>: 値T、または「値なし」(nullopt)を保持する。
  • 失敗時に std::nullopt を返す。
  • 呼び出し側では、if文で値の有無を判定し、.value()* で安全に値を取得する。
  • .value_or() を使えば、値がない場合のデフォルト値を指定できる。

optionalは、関数の戻り値として「成功したが結果は無効」といった状態を表現するのに最適で、エラーコードやマジックナンバー(番兵)を返す古いスタイルを置き換える、モダンなC++の機能です。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次