개념

std::optional은 C++17 표준 라이브러리에서 도입된 컨테이너로, 값이 있을 수도 있고 없을 수도 있는 값을 표현하는 타입이다. 널 포인터 대신 명시적으로 값의 유무를 표현할 수 있는 타입 안전한 대안으로 사용된다.

예를 들어 함수가 값을 반환할 수도, 반환하지 않을 수도 있는 경우 std::optional을 사용하여 반환값을 캡슐화할 수 있다.

기본 사용법

  #include <optional>
#include <iostream>

std::optional<int> divide(int numerator, int denominator) {
    if (denominator == 0)
        return std::nullopt;
    return numerator / denominator;
}

int main() {
    auto result = divide(10, 2);
    if (result)
        std::cout << "결과: " << *result << std::endl;
    else
        std::cout << "0으로 나눌 수 없습니다." << std::endl;
}
  

std::nullopt는 optional 객체가 값을 가지고 있지 않음을 나타내는 상수이다. *result는 optional 객체 내부의 값을 역참조하여 가져온다.

주요 멤버 함수

  • operator bool(): 값이 있으면 true, 없으면 false 반환
  • value(): 값이 없으면 예외를 던지고, 있으면 값을 반환
  • value_or(default_value): 값이 있으면 값을 반환하고, 없으면 기본값 반환
  • emplace(args...): 내부 값을 생성자 인자를 이용해 직접 생성
  • reset(): optional 객체를 비어 있는 상태로 리셋

생성자 예시

  #include <optional>
#include <string>
#include <iostream>

int main() {
    std::optional<std::string> opt1("hello");
    std::optional<std::string> opt2(std::in_place, 5, 'x');

    std::cout << *opt1 << std::endl;  // hello
    std::cout << *opt2 << std::endl;  // xxxxx
}
  

첫 번째 생성자는 문자열 리터럴로 초기화하고, 두 번째 생성자는 std::in_place를 사용해 std::string(5, 'x') 생성자를 직접 호출하여 초기화한다.

값 접근 방식

값에 접근할 땐 여러 방법이 있다.

  std::optional<int> opt = 10;

// 방법 1: operator*
int value1 = *opt;

// 방법 2: value()
int value2 = opt.value();

// 방법 3: value_or
int value3 = opt.value_or(0);
  

값이 없는데 *optopt.value()를 호출하면 **예외(std::bad_optional_access)**가 발생하므로 주의해야 한다.

nullopt

std::nullopt는 optional 객체를 비워두기 위해 사용한다.

  std::optional<int> opt1;           // 비어 있음
std::optional<int> opt2 = std::nullopt;  // 비어 있음
opt1 = 5;                          // 값 할당
opt2 = opt1;                       // 값 복사
opt1.reset();                      // 값 제거
  

std::nulloptstd::optional 타입과 함께 쓰이며, 값 없음 상태를 표현한다.

참조 optional

C++20부터 std::optional은 참조 타입(std::optional<int&>)도 지원한다.

  int x = 10;
std::optional<int&> ref = x;
if (ref)
    *ref = 20;
std::cout << x << std::endl;  // 20
  

참조 optional은 객체의 참조를 캡슐화하여 값이 있을 수도, 없을 수도 있는 참조를 다룰 수 있다.

참고 문서

https://en.cppreference.com/w/cpp/utility/optional