std::optional
std::optional은 C++17 부터 추가되었으며 변수나 오브젝트가 있을 수도 있고 없을수도 있다는 뜻을 의미한다.
예시로 다음 타입 스크립트 코드를 보면,
function f(x: number, y? : number)
{
return x + (y ?? 0)
}
여기서 y뒤에 물음표가 optional 인데
- y 값이 정의되어있으면 y를 그대로 사용하여 x에 더한다.
- y 값이 정의되어있지 않다면 0을 가져다 x에 더한다.
즉, 값이 있을수도 있고 없을수도 있다라는 것이다.
Example Code : Primitive Type 예제
#include <optional>
std::optional<int> divide(int a, int b)
{
if (b == 0)
{
return std::nullopt; // 정의될 수 없을 때는 nullopt을 리턴한다.
}
return a / b;
}
int main()
{
const auto ans = divide(10, 1);
if (answer) // 데이터 타입은 int의 Optional
{
std::cout << answer.value() << std::endl;
}
else
{
//std::cout << "no value" << std::endl;
std::cout << answer.value_or(0) << std::endl; // Default Value를 리턴해주는 것도 가능하다.
}
}
이러한 std::optional은 오브젝트를 사용해서 정의할 수도 있다.
Example Code : Object 정의
std::optional<Cat> cat;
if (!cat)
{
std::cout << "no cat yet" << std::endl;
}
이와 같은 방식으로 정의할 수 있는데 아직은 고양이 오브젝트가 없기 때문에 no cat yet이 출력된다.
처음에 고양이를 만들 때 오브젝트를 넣어줘야한다.
std::optional<Cat> cat{Cat()};
if (!cat)
{
std::cout << "no cat yet" << std::endl;
}
위 코드처럼 고양이 오브젝트를 만들어서 넘겨줄 수 있지만 문제가 있다. 이러한 방식은 임시 Cat 오브젝트가 만들어지고 move constructor를 통해서 초기화를 한다. 쓸데없이 고양이를 한 번 생성한 후에 move constructor를 사용하고 있기 때문에 효율적인 방법은 아니다.
std::optional<Cat> cat{std::in_place};
if (!cat)
{
std::cout << "no cat yet" << std::endl;
}
else
{
std::cout << "cat is ready" << std::endl;
cat->print(); // 화살표를 통해 호출
}
이 때, std::in_place라는 옵션을 넘겨주게 되면 optional이라는 공간안에 바로 고양이 오브젝트를 만들 수 있게 된다.
Memory model
int num = 10;
std::optional<int> num2{ 20 };
위와 같은 optional 코드를 사용했을 때 메모리 모델이 어떻게 되는지 확인해보면,
std::optional 변수는 왼쪽에 데이터 값 오른쪽 공간에 Valid한지 Valid하지 않은지 구분해 줄 수 있는 정보가 들어있다. 굉장히 간단한데 이게 optional 동작의 기본 원리의 전부이기 때문에 퍼포먼스에 유의미한 결과를 미치지는 않는다. std::pair보다는 코드 가독성이 좋아지기 때문에 C++ 17 이상을 지원한다면 사용을 고려하는 것이 좋다.
'C++ > Modern C++' 카테고리의 다른 글
[C++17] std::variant (0) | 2022.11.07 |
---|---|
[C++] Union (0) | 2022.11.04 |
[C++] 가상함수 원리 (0) | 2022.10.24 |
[C++] attributes(속성) (0) | 2022.10.13 |
[C++] Perfect forwarding (0) | 2022.10.05 |