[Modern C++] 항목 8: 0과 NULL보다 nullptr을 선호하라
카테고리: Cpp
이 글은 아래의 책을 정리하였습니다. 이펙티브 모던 C++, 스콧 마이어스 저자, 류광 번역
가독성이 떨어지는 직역들을 수정하며 정리하였습니다. e.g. 연역 → 추론, 중복적재 → 오버로딩
📦 3. 현대적 C++에 적응하기
👉🏻 항목 8: 0과 NULL보다 nullptr을 선호하라
// 3가지 함수 오버로딩
void f(int);
void f(bool);
void f(void*);
f(0); // f(int) 호출
// 컴파일 안될 가능성이 있으며, 보통은 f(int) 호출
// f(void*) 호출하는 경우는 없음
f(NULL);
f(nullptr); // f(void*) 호출
long → int,long → bool,0L → void*변환은 우선순위가 동일하다.0L(리터럴 0)과NULL은int형이다.- 포인터만 사용할 수 있는 위치에
0이 있다면,null포인터로 해석한다! NULL은long과 같은 정수 형식이 되는 경우도 희귀하게 존재한다.
- 포인터만 사용할 수 있는 위치에
nullptr은 정수/포인터 형식이 아닌, 모든 형식의 포인터이다.- 실제 형식은
std::nullptr_t이다. - 정수 형식으로 해석되지 않는다.
- 실제 형식은
- 포인터/정수 형식에 대한 오버로딩은 피해야 한다.
nullptr이 좋지만,0/NULL을 사용하는 개발자들이 여전히 있기 때문이다.
모든 형식의 포인터라고 부르는 이유:
nullptr_t→raw 포인터형식으로 암묵적 변환된다.
🔎 nullptr의 모호성 해결
// 반환형이 정수/포인터 중 무엇인지 알 수 없다면?
auto result = findRecord(...);
// 이것은 포인터인가, 정수인가?
if(result == 0) { ... }
// 모호성(ambiguity)가 없음!
if(result == nullptr) { ... }
🔧 nullptr과 템플릿
템플릿화 하기 전:
int f1(shared_ptr<Widget> spw);
double f2(unique_ptr<Widget> upw);
bool f3(Widget* pw);
std::mutex f1m, f2m, f3m;
using MuxGuard = std::lock_guard<std::mutex>;
{
MuxGuard g(f1m);
auto result = f1(0);
}
{
MuxGuard g(f2m);
auto result = f2(NULL);
}
{
MuxGuard g(f3m);
auto result = f3(nullptr);
}
템플릿화 (C++11):
int f1(shared_ptr<Widget> spw);
double f2(unique_ptr<Widget> upw);
bool f3(Widget* pw);
template<typename FuncType,
typename MuxType,
typename PtrType>
auto lockAndCall(FuncType func,
MuxType mutex,
PtrType ptr) -> decltype(func(ptr))
{
using MuxGuard = std::lock_guard<MuxType>;
MuxGuard g(mutex);
return func(ptr);
}
템플릿화 (C++14): 함수의 반환 형식에만 차이가 있다.
int f1(shared_ptr<Widget> spw);
double f2(unique_ptr<Widget> upw);
bool f3(Widget* pw);
template<typename FuncType,
typename MuxType,
typename PtrType>
decltype(auto) lockAndCall(FuncType func,
MuxType mutex,
PtrType ptr)
{
using MuxGuard = std::lock_guard<MuxType>;
MuxGuard g(mutex);
return func(ptr);
}
auto result1 = lockAndCall(f1, f1m, 0); // ① ⚠️ 오류!
auto result2 = lockAndCall(f2, f2m, NULL); // ② ⚠️ 오류!
auto result3 = lockAndCall(f3, f3m, nullptr); // ③ ✅
- ①②에서
0/NULL은 템플릿 형식 추론을 통해int형이 된다.shared_ptr,unique_ptr매개변수와 호환되지 않으므로 에러가 발생한다.
- ③에서
nullptr→(추론)nullptr_t→(암묵적 변환)Widget*순서로 처리된다.
🧐 정리
0과NULL보다nullptr을 선호하자.- 정수/포인터 형식에 대한 오버로딩을 피하자.
댓글남기기