값의 부재를 표현하고 싶다면 boost::optional

1 minute read

vec3 calc_respawn_position(...);

함수 시그니처(signature)만 보면 실패따윈 모르는 함수 같다. 팀이 약속한 vec3::invalid 같은 값도 없다.

아니네. 내부 구현을 보니 (0, 0, 0) 리턴. 이걸 실패 값으로 쓰는구나. 드러나지 않는 실패 값. 프로그래머가 내부 구현을 살펴보는지에 달렸다. 안 살펴보면 원점이 그냥 사용된다.

Consequently, absent values are traditionally expressed in C++ in one of 3 ways:

  1. Using ad-hoc special values, like EOF.
  2. Using ad-hoc additional flags, like pair<T,bool>.
  3. Using pointers even if the object would have been passed or returned by-value if it wouldn’t be possibly absent.

N1878

1번처럼 부재를 표현하는 특별한 값을 사용할 때 벌어지는 일이다. EOF처럼 특별한 녀석을 만들면 되는데, 그마저도 아니다.

bool calc_respawn_position(vec3* ret, ...);

이렇게 시그니처를 바꿔서 성공 여부를 표시할 수도 있다. 이런 시그니처가 많아서 단련은 됐다만 성공 여부와 결과값이 떨어져 있어 읽기가 편하진 않다. 이렇게 하는 이유는 성능 때문이다. 임시 객체 생성, 파괴. 복사 생성자 호출. 임시 생성 객체 생성을 막아주는 RVO가 있지만, 표준에 포함이 안 돼서 이걸 믿고 함수 설계를 하기는 망설여진다. 컴파일러에 의존하기 때문이다.

  1. [.] This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value

ISO/IEC 14882:2014(E). section 12.8

C++11에는 copy elision이란 이름으로 들어갔다. return 고고.

매번 std::pair<T, bool> 을 정의해서 쓰는 것 보단 하나 만들어서 닳을 때까지 쓰자. boost::optional 사용도 좋다. boost 사용이 망설여지면 하나 만들면 된다. akrzemi1/optional을 참고하는 걸 추천.

const boost:optional<vec3> pos = calc_respawn_position(...);
if (pos) {
    teleport(*pos)
        } else {
    // ...
}

값의 부재가 명확해졌다. optional return values 말고도 다른 사용 예제를 quick start에서 찾아볼 수 있다.

bool을 initialization flag로 사용하기 때문에 메모리 레이아웃 빵구는 안고 가야 한다. 이게 싫고 실패로 사용하는 특별한 값이 있다면 compact_optional도 고려해볼 만하다.

Optional is proposed for Fundamentals TR rather than 2014 C++ Standard. It is now in namespace std::experimental and in header <experimental/optional>.

N3793

std::optional이 C++14에 들어간 줄 알았다. 아니네. C++17에는 볼 수 있으려나?

표준에 뭔가 추가하는 사람 존경해야겠다. std::optional은 revision 5 까지 왔다.