본문 바로가기
개발/C++ (98,03,11,14,17,20,23)

Modern C++ : std::optional (17)

by snowoods 2025. 9. 28.

Modern C++

 

std::optional

 

개요

std::optional은 C++17부터 도입된 기능으로, 값이 있을 수도 있고 없을 수도 있는 상황을 명시적으로 표현하는 데 사용되는 템플릿 클래스입니다. 함수가 유효한 값을 반환하지 못하는 경우, 이전에는 nullptr나 특별한 값(예: -1)을 반환하여 실패를 알렸습니다. std::optional은 이러한 상황을 더 안전하고 명확하게 처리할 수 있는 방법을 제공합니다.

 

C++ 버전별 주요 키워드 도입 시기

  • C++17: std::optional 도입

 

내용 설명

std::optional<T> 객체는 타입 T의 값을 포함하거나, 아무 값도 포함하지 않는 두 가지 상태를 가질 수 있습니다. 값이 없는 상태는 std::nullopt를 사용하여 표현합니다.

주요 멤버 함수는 다음과 같습니다.

  • has_value(): optional 객체가 값을 가지고 있는지 확인합니다. (bool 반환)
  • value(): 저장된 값을 반환합니다. 값이 없는 경우 std::bad_optional_access 예외를 발생시킵니다.
  • value_or(default_value): 저장된 값을 반환합니다. 값이 없는 경우 default_value를 반환합니다.
  • operator*, operator->: 저장된 값에 직접 접근합니다. 값이 없는 상태에서 호출하면 정의되지 않은 동작(undefined behavior)을 유발하므로, has_value()로 확인 후 사용해야 합니다.

 

예제 코드

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

// C++17 이상에서 컴파일해야 합니다.

using namespace std::string_literals;

// 플래그에 따라 문자열을 반환하거나, 아무것도 반환하지 않는 함수
std::optional<std::string> check(const bool flag)
{
    if (flag)
        return "true"s; // 값을 포함하는 optional 반환
    return {}; // std::nullopt와 동일. 비어있는 optional 반환
}

int main()
{
    // 1. 값 초기화 및 접근
    auto v1 = std::optional<int>{42};
    if (v1.has_value()) // if (v1) 와 동일
    {
        std::cout << *v1 << '\n'; // 포인터처럼 접근
    }

    // 2. value() 와 value_or()
    auto v2 = std::optional<std::string>{"text"s};
    std::cout << v2.value() << '\n'; // 예외 위험 있지만, 값 존재 시 안전

    auto v3 = std::optional<std::string>{}; // 비어있음
    std::cout << v3.value_or("default"s) << '\n'; // 비어있을 때 기본값 사용

    // 3. has_value()로 상태 확인
    std::cout << std::boolalpha << v2.has_value() << '\n';
    std::cout << std::boolalpha << v3.has_value() << '\n';

    // 4. 함수 반환값으로 활용
    auto res1 = check(true);
    std::cout << "check(true): " << res1.value_or("empty") << '\n';

    auto res2 = check(false);
    std::cout << "check(false): " << res2.value_or("empty") << '\n';

    return 0;
}

 

실행 결과

42
text
default
true
false
check(true): true
check(false): empty

 

활용팁

  • 함수 반환 값: 값을 반환할 수도, 그렇지 않을 수도 있는 함수의 반환 타입으로 std::optional을 사용하면 API의 의도가 명확해집니다.
  • 안전한 값 접근: value()는 값이 없을 때 예외를 던져주므로 프로그램의 비정상적인 상태를 조기에 발견하는 데 도움이 됩니다. 반면, value_or()는 값이 없을 때의 기본 흐름을 안전하게 처리할 때 유용합니다.
  • 성능: 값이 존재함이 확실한 상황에서는 * 또는 -> 연산자를 사용하면 value()의 예외 처리 오버헤드를 피할 수 있어 약간의 성능 이점을 얻을 수 있습니다.