본문 바로가기
NC University/Advanced C++

4일차 - nullptr

by 날쑤 2015. 8. 3.

Intro

  C언어에서는 포인터 변수가 가리키는 주소가 없을 경우에 NULL을 사용했다. 그리고 C++에서도 11로 넘어오기 전에는 C와 같이 NULL을 사용했었다. 그런데 이 NULL의 정체를 살펴보면 정수값 '0'을 이용해서 정의하고 있다. 그렇기 때문에 아래 코드에 나온 것 처럼 0을 이용해서 포인터 변수를 초기화하거나 함수에 포인터 인자를 넘길때 0을 사용할 수 있다.

  위의 코드를 보면 NULL이 정상적으로 동작하려면 (void*)0으로 정의되어야 할 것처럼 보인다. 이는 같은 이름의 함수가 하나는 정수 타입의 인자를, 다른 하나는 포인터 인자를 받도록 정의되어 있을 경우에 NULL이 0으로 정의되었다면 오버로딩 규칙에 의해 foo(NULL)은 정수 타입 인자를 받는 함수를 호출할 것이기 때문이다.그렇지만 이러한 정의는 C++에서 다른 문제를 야기시킨다.

  결국 C++에서는 위에서 언급한 오버로딩 문제를 감수하더라도 NULL을 다음과 같이 정의하는 게 최선이며, 실제로도 이렇게 정의되어있다.

nullptr

  문제의 근본적인 원인은 Null 포인터의 값을 정수 값을 이용해서 정의했기 때문이다. 그러므로 이 상황을 해결하려면 Null 포인터를 위한 새로운 타입을 정의하고, NULL 포인터를 이 타입의 값으로 표현해야 한다. 또한, NULL 포인터는 모든 포인터 타입에 적용될 수 있어야하므로 이 새로운 타입은 모든 포인터 타입으로 암시적 변환이 가능해야 한다. C++ 11부터는 이러한 조건들을 모두 충족시키는 nullptr이 등장해서 기존의 NULL을 대체한다.

  위의 코드는 nullptr의 특징들을 설명하고 있다. 우선 nullptr은 포인터 변수만을 위한 값이다. 이를 위해 nullptr_t라는 새로운 타입을 정의했으며, 이 새로운 타입은 더이상 정수 타입과 호환이 되지 않는다. 특이한 점은 nullptr과 bool타입의 호환이 가능하다는 점인데, 이는 nullptr이 if문 내에서 부정의 의미로 사용될 수 있기 때문이다.

nullptr의 필요성

  현재는 오버로딩 문제를 제외하면 함수로 포인터 인자를 넘길 때 Null 포인터 값으로 0, NULL, 그리고 nulptr, 3개 중에 어떤 것을 넘기더라도 문제가 되지 않는다. 하지만 완벽한 전달 문제가 개입되면 상황이 달라진다. 아래의 코드는 이를 보여준다.