주간 팁 #163: <code>std::optional</code>
매개변수 전달하기
원래 TotW #163으로 2019년 7월 11일 게시됨
작성자: Ian Eldred Pudney
2020-04-06 업데이트됨
빠른 링크: abseil.io/tips/163
Null 참조는 정말로 10억 달러의 실수일까요?
문제
매개변수가 존재할 수도 있고 존재하지 않을 수도 있는 함수를 구현해야 한다고 가정해봅시다. 이 경우, 현대적인 std::optional
을 사용하고 싶은 유혹을 받을 수 있습니다. 그러나 객체가 충분히 커서 참조로 전달해야 한다면, std::optional
은 적합하지 않을 수 있습니다. 다음 두 선언을 살펴보세요:
void MyFunc(const std::optional<Foo>& foo); // 값 복사 가능성 있음
void MyFunc(std::optional<const Foo&> foo); // 컴파일되지 않음
첫 번째 옵션은 아마도 원하는 동작을 수행하지 않을 것입니다. 만약 누군가 std::optional<Foo>
를 MyFunc
에 전달하면 참조로 전달되지만, 누군가 Foo
를 (예: 반환 값으로) 전달하면, Foo
가 임시 std::optional<Foo>
로 값 복사된 후 함수에 참조로 전달됩니다. 복사를 피하려고 했던 목적이 달성되지 않는 것이죠.
두 번째 옵션은 훌륭할 것 같지만, 불행히도 std::optional
에서는 지원되지 않습니다.
권장 사항
const std::optional&
형태의 함수 매개변수를 피하세요.
객체가 참조로 전달할 만큼 크지 않은 경우, std::optional
로 감싼 객체를 값으로 전달하세요. 예를 들어:
void MyFunc(std::optional<int> bar);
void MyFunc(std::optional<absl::string_view> baz);
매개변수의 복사를 의도적으로 수행하는 경우에도 std::optional
을 값으로 전달하여 이를 명확히 하세요:
void MyFunc(std::optional<Foo> foo);
그 외의 경우, std::optional
을 완전히 생략하세요. 대신 absl::Nullable<const Foo*>
를 사용하고, nullptr
로 “존재하지 않음”을 나타낼 수 있습니다.
void MyFunc(absl::Nullable<const Foo*> foo);
이 방식은 const Foo&
로 전달하는 것만큼 효율적이며 null 값을 지원합니다. 포인터 대신 const 참조를 사용할 때에 대한 자세한 내용은 팁 #116을 참조하세요.
그렇다면 도대체 std::optional
은 어디에 사용해야 할까요?
std::optional
은 선택적인 객체를 소유해야 하는 경우에 사용할 수 있습니다. 예를 들어, 클래스 멤버 또는 함수 반환 값에 적합합니다.
예외 사항
모든 호출자가 이미 std::optional<Foo>
를 가지고 있고 절대 Foo
만 전달하지 않을 것으로 예상되는 경우, const std::optional<Foo>&
를 사용할 수 있습니다. 그러나 이는 드문 경우로, 일반적으로 함수가 파일/라이브러리 내부에서만 사용하는 private 함수일 때만 해당됩니다.
std::reference_wrapper
는 어떨까요?
std::optional
문서는 optional 참조를 지원하지 않는 문제를 해결하기 위해 std::reference_wrapper
를 사용할 수 있다고 언급합니다:
void MyFunc(std::optional<std::reference_wrapper<const Foo>> foo);
그러나, 우리는 이를 권장하지 않습니다:
std::reference_wrapper
는 놀랍도록 미묘한 동작 방식을 가지며, 이해하고 안전하게 사용하기 어렵습니다. 예를 들어, 표준 라이브러리의 다양한 유틸리티는 이를 특별히 처리하여 일반 값 또는 참조와 다르게 동작하게 합니다.std::optional<std::reference_wrapper<const Foo>>
는absl::Nullable<const Foo*>
에 비해 장황하고 사용하기 불편합니다.
결론적으로, 함수 매개변수로 std::optional
을 사용할 때는 상황에 맞게 신중하게 선택해야 합니다.