소년코딩

07.08 - 널 포인터 (Null pointer)

Null values and null pointers

일반 변수와 마찬가지로 포인터는 인스턴스화 될 때 초기화되지 않는다. 값이 할당되지 않으면 포인터는 기본적으로 어떤 가비지 주소를 가리킨다.

메모리 주소 외에도 포인터가 저장할 수 있는 값이 하나 있다. 바로 null 값이다. null 값은 포인터가 아무것도 가리키지 않는다는 것을 의미하는 특수 값이다. null 값을 가진 포인터를 null 포인터라고 한다.

C++에서 포인터로 null 값을 지정하려면 리터럴 0으로 초기화하거나 할당하면 된다.

float* ptr { 0 };  // ptr is now a null pointer

float* ptr2;       // ptr2 is uninitialized
ptr2 = 0;          // ptr2 is now a null pointer

포인터가 null이면 부울값 false로, null이 아닌 경우에는 불린 값 true로 반환된다. 따라서 조건부를 사용하여 포인터가 null인지 여부를 테스트할 수 있다.

double* ptr { 0 };

// pointers convert to boolean false if they are null, and boolean true if they are non-null
if (ptr)
    cout << "ptr is pointing to a double value.";
else
    cout << "ptr is a null pointer.";

다른 값을 지정하지 않을 땐 포인터를 null 값으로 초기화하자.


Dereferencing null pointers

이전 포인터 포스트에서 가비지 포인터의 역참조는 정의되지 않은 결과를 초래할 것이라고 언급했다. null 포인터를 역참조하면 정의되지 않은 동작이 발생한다. 대부분은 응용 프로그램이 중단된다.

개념적으로 이것은 의미가 있다. 포인터를 역참조한다는 것은 '포인터가 가리키는 주소를 이동하여 그 값에 접근'을 의미한다. 널 포인터에는 주소가 없다. 따라서 해당 주소의 값에 접근하려면 어떻게 해야 할까?


NULL macro

C 언어는 값 0으로 #definedNULL 이라는 특수 전처리기 매크로가 있다. 기술적으로 C++의 일부는 아니지만, 사용법은 모든 C++ 컴파일러에서 작동할 만큼 일반적이다.

double* ptr { NULL }; // assign address 0 to ptr

그러나 NULL은 전처리기 매크로이며 기술적으로 C++의 일부가 아니므로 C++에서는 사용을 피하는 것이 좋다.


nullptr in C++11

값 0은 포인터 유형이 아니므로 포인터가 null 포인터임을 나타내기 위해 포인터에 0을 할당하는 것은 일관성이 없다. 드문 경우지만, 리터럴 0을 사용할 경우 컴파일러에서 null 포인터를 의미하는지 정수 0을 의미하는지 확인할 수 없으므로 문제가 발생할 수 있습니다.

doSomething(0); // is 0 an integer argument or a null pointer argument?  (It will assume integer)

이러한 문제를 해결하기 위해 C++ 11에서는 nullptr이라는 새로운 키워드를 도입했다. nullptrtruefalse와 같은 불린 키워드와 마찬가지로 키워드 및 r-value 상수다.

int *ptr { nullptr }; // note: ptr is still an integer pointer, just set to a null value

C++은 암시적으로 nullptr을 포인터 모든 유형으로 변환한다. 따라서 위의 예에서 nullptr은 암시적으로 정수 포인터로 변환된 다음 nullptr 값이 ptr에 할당된다. 이것은 정수 포인터 ptr을 널 포인터로 만드는 효과가 있다.

이것은 nullptr 리터럴로 함수를 호출하는 데에도 사용할 수 있다.

#include <iostream>

void doSomething(double* ptr)
{
    // pointers convert to boolean false if they are null, and boolean true if they are non-null
    if (ptr)
        std::cout << "You passed in " << *ptr << '\n';
    else
        std::cout << "You passed in a null pointer\n";
}

int main()
{
    doSomething(nullptr); // the argument is definitely a null pointer (not an integer)

    return 0;
}

Best practice: C++ 11에서는 nullptr을 사용해서 포인터를 null 값으로 초기화하자.


std::nullptr_t in C++11

C++ 11은 또한 <cstddef> 헤더에 잇는 std::nullptr_t라는 새로운 유형을 도입했다. std::nullptr_tnullptr 하나의 값만 가질 수 있다. 이것은 어리석은 것처럼 보이지만 한 가지 상황에서 유용하다. nullptr 인자를 받아들이는 함수를 작성하고자 하면 어떤 타입의 매개 변수를 만들까? std::nullptr_t이다.

#include <cstddef> // for std::nullptr_t

void doSomething(std::nullptr_t ptr)
{
    std::cout << "in doSomething()\n";
}

int main()
{
    doSomething(nullptr); // call doSomething with an argument of type std::nullptr_t

    return 0;
}

아마도 이것을 사용할 필요가 없을 수 있다. 하지만 만약을 위해 알아두는 게 좋다.


cpp 번역: 이 포스트의 원문은 http://www.learncpp.com/cpp-tutorial/6-7a-null-pointers/ 입니다.

댓글 로드 중…

블로그 정보

소년코딩 - 소년코딩

소년코딩, 자바스크립트, C++, 물리, 게임 코딩 이야기

최근에 게시된 이야기