[Effective Modern C++] 항목 8: NULL, 0 대신 nullptr을 쓰기
우리는 흔히 null pointer를 인자로 넘길 때 0을 쓰곤 한다. C++은 포인터가 사용돼야 하는 상황에서 0을 본다면 마지못해 null pointer로 그것을 해석한다. 하지만 엄밀히 0은 int이다.
NULL도 마찬가지이다. NULL의 구현은 때에 따라 다르지만, 보통 int나 long으로 구현되어 있다.
아무튼 이로 인해 C++98에서는 pointer와 integral type의 function overloading을 피하곤 했다. 이는 C++11에서도 유효한데, 왜냐하면 아직도 많은 개발자들이 0과 NULL을 null pointer을 나타내기 위해 쓰기 때문이다(nullptr이 더 좋은 선택임에도 불구하고!).
예시를 보자.
void f(int); // three overloads of f
void f(bool);
void f(void*);
f(0); // calls f(int), not f(void*)
f(NULL); // might not compile, but typically calls f(int).
// Never calls f(void*)
integral type과 pointer overloaded function에서는 f(0)과 f(NULL)은 f(void*)를 부를 수 없다!
nullptr을 쓰는 것의 이점은, 그것이 integral type이 아니란 것이다. 사실 pointer type도 아니다. nullptr은 std::nullptr_t의 타입을 갖고 있다. std::nullptr_t는 implicit 하게 모든 raw pointer type으로 변환된다.
위의 예시에서 f(nullptr)은 f(void*)를 부른다!
또 다른 장점은, 코드의 가독성을 높여준다는 것이다. 특히, auto가 사용된 다음 예시를 보자.
auto result = findRecord( /* arguments */ );
if (result == 0) {
…
}
위의 코드만 봐서는 findRecord 함수가 return하는 것이 integral type인지 pointer type인지 알 수 없다.
하지만,
auto result = findRecord( /* arguments */ );
if (result == nullptr) {
…
}
이렇게 짠다면, findRecord가 return하는 값은 pointer type이란 것을 명확히 알 수 있다.
nullptr의 이점은 template을 쓸 때도 나타난다. 우선 다음 예시를 보자.
int f(std::shared_ptr<int> spw);
auto result = f(0);
위 코드는 문제없이 컴파일된다. f는 포인터 타입을 인자로 받는 함수인데, 0이 들어왔으므로 '마지못해' null ptr로 해석하게 된다. 하지만 템플릿을 사용하는 다음의 경우는 다르다.
int f(std::shared_ptr<int> spw);
template<typename FuncType,
typename PtrType>
decltype(auto) templateFunc(FuncType func, // C++14
PtrType ptr)
{
return func(ptr);
}
auto result = templateFunc(f, 0);
이 경우는 PtrType이 int가 되고, func에 int type을 넘겨주려 했기 때문에 컴파일 에러가 발생한다.
아까랑 뭐가 다른거지? 라고 생각할 수도 있는데, f(1)은 컴파일 에러가 발생하는 이유와 같다.
f(0)을 직접적으로 호출하면 마지못해 null ptr로 변환하지만, 템플릿을 사용하면 명확한 타입 추론이 먼저 발생하므로, 0을 인자로 넘긴다 한들 0을 null ptr로 해석하는 특수성을 고려하지 않는 것이다!
요약
- nullptr를 쓰면 pointer와 integral type의 overload 상황에서 pointer를 인자로 갖는 함수를 호출할 수 있고, 코드의 가독성이 좋아지며, 템플릿을 사용할 때도 의도한 대로 동작할 수 있다. 따라서 nullptr을 쓰자!
- 그럼에도 불구하고 integral과 pointer type에 대해서 overloading은 피하자.