Skip to main content

Boost에서 시작된 std::optional, C++26에 이르기까지의 진화와 실전 활용 가이드

Published 4 min readMarkdown

# 서론 – 왜 std::optional을 알아야 할까?

C++ 개발자는 종종 “값이 없을 수도 있는 상황”을 어떻게 표현할지 고민합니다.

예전에는 nullptr, 특별한 플래그 값, 혹은 boost::optional 같은 서드파티 라이브러리를 사용했죠.

하지만 C++ 표준에 std::optional이 도입되면서 코드 가독성과 안전성이 크게 향상되었습니다.

이번 글에서는 Boost.Optional에서 시작해 C++26에 이르는 std::optional의 역사를 짚어보고, 초보자도 바로 적용할 수 있는 실전 예제를 제공합니다.


# 1️⃣ Boost.Optional의 등장 배경

  • Boost는 C++ 표준화 이전에 다양한 유용한 기능을 제공하던 커뮤니티 프로젝트였습니다.

  • boost::optional<T>는 “값이 존재하거나 존재하지 않을 수 있는” 상황을 타입 시스템으로 명시해 주는 첫 번째 시도였으며, 다음과 같은 장점을 가졌습니다.

    1. 명시적인 의도 – 함수 반환값이 null일 수 있음을 컴파일 타임에 알림.

    2. 안전한 접근 – operator*, operator-> 사용 전 has_value() 검사 강제.

    3. 복사·이동 지원 – 일반 객체와 동일하게 복사·이동이 가능.

하지만 Boost는 별도 라이브러리이기 때문에 빌드 설정이 복잡하고, 표준 라이브러리와의 일관성이 부족했습니다. 이러한 한계가 std::optional 표준화의 동기가 되었습니다.


# 2️⃣ std::optional의 표준 채택 과정

| 연도 | 주요 사건 |

|------|-----------|

| 2014 | C++14 회의에서 optional 초안 제안. |

| 2015 | N4387 “Optional object for C++” 초안 발표. |

| 2017 | C++17 최종 표준에 std::optional 포함. |

| 2022 | C++20에서 std::optional 관련 constexpr 개선. |

| 2025 | C++26에서 std::optional::transform 과 or_else 등 새로운 멤버 함수 추가. |

# 핵심 변화

  1. constexpr 지원 확대 – C++20부터 대부분의 멤버가 constexpr이 되어 컴파일 타임 연산이 가능해졌습니다.

  2. operator== 자동 생성 – 구조화 바인딩과 비교 연산이 간편해졌습니다.

  3. C++26 신규 API – transform, or_else, swap 등이 추가돼 함수형 스타일 코딩이 쉬워졌습니다.

이러한 진화 덕분에 std::optional은 이제 값이 없을 때를 다루는 가장 직관적인 표준 도구가 되었습니다.


# 3️⃣ C++26에서 도입된 새로운 기능

# 3.1 transform – 함수형 스타일 매핑

cpp

std::optional<int> opt = 42;

auto doubled = opt.transform([](int v){ return v * 2; }); // doubled = std::optional<int>{84}
  • opt가 값이 있으면 람다를 적용하고, 없으면 빈 optional을 반환합니다.

  • std::optional을 파이프라인처럼 연결할 수 있어 코드가 깔끔해집니다.

# 3.2 or_else – 대체값 제공

cpp

std::optional<std::string> name = std::nullopt;

auto result = name.or_else([]{ return std::make_optional<std::string>('Anonymous'); });
  • 값이 없을 경우 지정한 콜백을 실행해 새로운 optional을 반환합니다.

  • 기존 value_or와 달리 지연 평가가 가능해 비용이 큰 연산을 필요할 때만 수행합니다.

# 3.3 swap – 두 optional 교환

cpp

std::optional<int> a = 10, b = std::nullopt;

a.swap(b); // a = nullopt, b = 10
  • std::swap보다 명시적이며, noexcept 보장을 제공합니다.

# 4️⃣ 실전 코드 예제 – 파일 읽기와 옵션 반환

아래 예제는 파일을 열고 첫 번째 라인을 읽어 std::optional<std::string> 로 반환합니다.

C++17 이전에는 boost::optional이나 nullptr 체크가 필요했지만, 이제는 한 줄 코드로 구현됩니다.

cpp

# include <optional>

# include <fstream>

# include <string>

std::optional<std::string> read_first_line(const std::string& path)

{
    std::ifstream file(path);

    if (!file) return std::nullopt;               // 파일 열기에 실패하면 빈 optional 반환

    std::string line;

    if (std::getline(file, line))

        return line;                              // 성공하면 값이 있는 optional 반환

    return std::nullopt;                         // 파일이 비어있어도 빈 optional

}

// C++26에서 transform, or_else 활용

void demo(const std::string& path)

{
    auto upper = read_first_line(path)

        .transform([](auto&& s){                 // 첫 라인을 대문자로 변환

            std::string r;

            for (char c : s) r += std::toupper(c);

            return r;

        })

        .or_else([]{ return std::make_optional<std::string>('NO DATA'); });

    // 여기서 upper는 반드시 값이 존재한다.

    std::cout << 'Result: ' << *upper << '\n';

}
  • 핵심 포인트

    • std::nullopt 로 “값 없음”을 명시.

    • transform 으로 값이 있을 때만 변환 로직 실행.

    • or_else 로 값이 없을 경우 대체 문자열을 지연 생성.

초보자도 위 코드를 그대로 복사해 프로젝트에 적용하면, 안전하고 가독성 좋은 옵션 처리를 경험할 수 있습니다.


# 결론 – 지금 바로 std::optional을 프로젝트에 도입하세요!

Boost.Optional이 남긴 유산은 표준화된 std::optional에 그대로 이어졌습니다.

C++26에서 추가된 transform, or_else, swap 같은 최신 API를 활용하면 함수형 프로그래밍 스타일도 자연스럽게 구현할 수 있습니다.

행동 유도

  1. 현재 프로젝트가 C++17 이하라면 boost::optional을 임시로 사용해 보세요.

  2. 컴파일러를 C++26 모드(-std=c++26)로 전환하고, 위 예제를 그대로 적용해 보세요.

  3. 팀 코드 리뷰 시 std::optional 사용 규칙을 정해, 일관된 옵션 처리 방식을 만들면 코드 품질이 크게 향상됩니다.

std::optional은 이제 C++ 개발자의 필수 도구입니다. 오늘부터라도 하나의 함수에라도 적용해 보면서, “값이 없을 수도 있다”는 상황을 더 명확하게 표현해 보세요.


SEO 키워드: std::optional, C++26, Boost.Optional

No comments yet. Be the first to comment.

More from this blog