C++ 에서 쓰이는 NULL 은 0과 동일하다.
가리키는 포인터가 없으면 그 주소는 0이기 때문이다.
stdio.h 에서 NULL을 정의하는 부분을 살피면 한 번에 알 수 있다.
/- Define NULL pointer value *-
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
NULL 과 0, 동일한 int 타입이다.
nullptr 을 쓰는이유
(1) 오동작 방지
void Test(int a)
{
cout<< "Test(int)" <<endl;
}
void Test(void* ptr)
{
cout<< "Test(*)" <<endl;
}
// 본문
int main()
{
Test(0); // Test(int a) 함수 호출
Test(NULL); // Test(int a) 함수 호출
Test(nullptr); // Test(void* ptr) 함수 호출
}
두 Test 함수 중에서 아래의 함수인 포인터를 활용하고 싶음에도 불구하고, NULL == 0 이므로 자동으로 Test(int a) 함수를 호출하는 상황이 생긴다. 그러나 nullptr 를 인자로 넣었을 때는 Test(void* ptr) 함수를 호출 할 수 있다.
이처럼 nullptr는 사용하는 함수가 overloading 되어 있을 때, 0이나 NULL을 썼을 경우에 제대로 호출되지 않는 문제를 해결 할 수 있다.
이런 오동작을 방지하기 위해서라도 nullptr 를 쓴다.
(2) 가독성이 높아진다
// 클래스 만들어주기
class Object
{
// empty
};
Object* findObject()
{
return nullptr;
};
int main()
{
auto object = findObject();
if(object == nullptr)
{
return 0;
}
return 0;
}
auto를 사용하게 될 경우, 코드를 그냥 쭉 읽었을 때 이 object 의 자료형을 쉽게 추론하기 어렵다. findObject라는 함수의 반환값을 찾아보면 알 수는 있겠지만, F12를 눌러 또 타고 들어가야 하는 귀찮음이 동반되니까.. (사실 뭐.. F12하나 누르는게 뭐가 귀찮냐고 할 수도 있지만..)
이 때 nullptr 를 보고, "아~ 포인터를 저장하는 변수구나" 하고 쉽게 알게 된다.
이러한 가독성을 높이는데 도움을 준다.
Nullptr를 구현해보기
class NULLptr
{
public:
// 그 어떤 타입의 포인터와도 치환 가능
template<typename T>
operator T* () const
{
return 0;
}
// 그 어떤 타입의 멤버 포인터와도 치환 가능
template<typename C, typenameT>
operator T C::* () const
{
return 0;
}
// 주소값 유출을 막는다
void operator&() const = delete;
};
// nullptr 과 동일한 역할을 할 수 있게 된다.
const NULLptr _NULLptr;
참고로 nullptr의 타입은 std::nullptr_t 로,
기존에 사용하던 NULL이나 0을 static_cast를 사용해서 nullptr 로 캐스팅이 가능하다.
int* ptr1 = static_cast<std::nullptr_t>(NULL);
int* ptr2 = static_cast<std::nullptr_t>(0);
참고 : [C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문 강좌 - Rookiss