std::optional, std::variant, std::any: 값이 없거나 여러 형태일 때
18강. std::optional, std::variant, std::any: 값이 없거나 여러 형태일 때
이번 강의에서 해결할 문제
조회 실패를 빈 문자열이나 -1로 표현하면 정상 값과 구분이 어렵습니다. 여러 결과 타입을 void*로 전달하면 타입 검사가 실행 시점까지 미뤄집니다. C++17의 vocabulary type은 가능한 상태를 타입에 기록합니다.
학습 목표
먼저 알아야 할 핵심 개념
optional<T>는 T 값이 있거나 없는 두 상태입니다. variant<A, B>는 미리 정한 타입 중 정확히 하나를 보관합니다. any는 복사 가능한 임의 타입을 저장하지만 소비자가 타입을 알아야 하고 잘못된 cast는 예외가 되므로 경계가 불명확해질 수 있습니다.
왜 이 문제가 위험한가
빈 optional을 value()로 읽으면 예외가 나고 *value는 전제 위반이 됩니다. variant의 모든 대안을 처리하지 않으면 새 타입 추가 시 논리 누락이 생깁니다. any를 일반 메시지 상자처럼 쓰면 컴파일러가 타입 관계를 검증하지 못합니다.
가장 작은 예제로 시작하기
#include <iostream>
#include <optional>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>
struct FoundTask { std::string name; };
struct MissingTask { int id{}; };
using LookupResult = std::variant<FoundTask, MissingTask>;
std::optional<std::string> findName(const std::vector<std::string>& names, std::size_t index) {
if (index >= names.size()) return std::nullopt;
return names[index];
}
int main() {
const std::vector<std::string> names{"build", "test"};
if (const auto name = findName(names, 1)) std::cout << *name << '\n';
LookupResult result = MissingTask{7};
std::visit([](const auto& value) {
if constexpr (std::is_same_v<std::decay_t<decltype(value)>, FoundTask>)
std::cout << value.name << '\n';
else
std::cout << "missing:" << value.id << '\n';
}, result);
}
코드 한 줄씩 이해하기
findName은 값이 없을 수 있음을 반환 타입에 표시합니다.- 호출자는 optional의 참 여부를 확인한 뒤 역참조합니다.
LookupResult는 성공과 실패 상세 중 하나를 보관합니다.visit가 현재 활성 타입에 맞는 분기를 호출합니다.if constexpr는 선택되지 않은 타입 분기를 컴파일하지 않습니다.
실행 결과와 메모리·동작 흐름
출력은 test, missing:7입니다. optional은 문자열 값을 자체 수명으로 보관하므로 원본 vector 주소를 장기 관찰하지 않습니다. variant는 MissingTask를 활성 대안으로 보관합니다.
단계별 실습
흔한 실수와 해결 방법
언제 사용하고 언제 피할까
정상적인 값 없음은 optional, 닫힌 대안 집합은 variant, 외부 확장 지점처럼 타입을 컴파일 시점에 제한할 수 없는 경계만 any를 고려합니다. 실패 원인이 여러 가지라면 optional보다 명시적 결과 타입이 낫습니다.
게임 개발 연결
선택 대상 없음, 명령 결과, 효과 종류처럼 상태가 분명한 곳에 적용할 수 있습니다. 엔진 전용 타입으로 옮기기 전에 표준 C++ 타입이 표현하는 의미를 먼저 정합니다.
이해 점검 질문 3개
- optional이 빈 문자열이나 -1보다 값 없음의 의미를 잘 표현하는 이유는 무엇인가요?
- variant와 any는 가능한 타입 집합에서 어떻게 다른가요?
- 실패 원인을 사용자에게 알려야 할 때 optional만으로 부족할 수 있는 이유는 무엇인가요?
핵심 요약
다음 강의 연결
19강. 예외와 오류 처리에서 실패 상태를 어디에서 복구하고 어떻게 호출자에게 전달할지 결정합니다.
std::optional, std::variant, std::any: 값이 없거나 여러 형태일 때 미니 퀴즈
선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.
학습을 마쳤나요?
직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.