카테고리 없음

허상 포인터 (Dangling Pointer), 와일드 포인터(Wild Pointer)

cjeongmin 2022. 9. 28. 17:11

허상 포인터, 와일드 포인터

허상 포인터, 와일드 포인터는 컴퓨터 프로그래밍에서 유효한 객체를 가르키고 있지 않는 포인터를 말한다.

허상 포인터

허상 포인터는 객체 파괴시에 발생하는데, 즉 객체에 대한 참조가 포인터 값에 대한 수정 없이 삭제되거나 할당 해제돼서 포인터가 계속 할당 해제된 메모리를 가르키는 때 발생한다.
시스템은 할당 해제된 메모리를 다른 프로세스에게 재할당하겠지만, 기존 프로그램이 허상 포인터를 역참조하면 메모리는 현재 전혀 다른 데이터를 갖고 있을 것이므로 예측할 수 없는 행동이 발생하게 된다. 특히 프로그램이 허상 포인터가 가리키는 메모리에 쓰기를 하면, 관련되지 않은 데이터의 조용한 오염이 발생하게 되고, 이것은 찾기가 매우 힘들어진다. 참고로 리눅스, 유닉스의 경우에는 세그멘테이션 오류가, 윈도우의 경우에는 일반 보호 오류가 발생하게 된다. 만약 이 겹쳐써진 데이터가 시스템의 메모리 할당자가 사용하는 북키핑 데이터라면, 이 오염은 시스템을 불안정하게 만들 수 있다. GC(Garbage Collection)가 있는 프로그래밍 언어에서는 허상 참조들은 참조되지 않는 객체를 파괴함으로써 예방된다.

와일드 포인터

와일드 포인터들은 포인터가 알려진 상태로 초기화되기 전에 사용될 때 발생한다. 이것은 허상 포인터와 같은 오류적인 행동들을 보이지만, 탐지되기가 쉽다는 차이점이 있다.

허상 포인터 피하기

허상 포인터를 피하는 방법 중 가장 쉬운 것은 포인터를 재설정하는 메모리 해제 함수를 만드는 것이다.
그러나 이 포인터의 복사본을 갖는 다른 포인터 변수들까지 보장하지는 않는다.
예시로, 아래 코드에서 destruct 함수에서 메모리 해제 후, root 포인터를 NULL의 값으로 주고 있다.
하지만 이러한 방식은 실수를 유도할 수 있어 함수로 따로 만들거나 매크로로 만들어 좀 더 실수를 줄이는 방식으로 개선할 수 있다.

#include <iostream>
using namespace std;

struct Node {
    int data;
    struct Node *left;
    struct Node *right;
};

void insert(Node **root, int data);
...
void destruct(Node **root);

int main() {
    ...
    return 0;
}



void insert(Node **root, int data) {
    if (*root == NULL) {
        Node *node = new Node();
        node->data = data;
        node->left = node->right = NULL;
        *root = node;
        return;
    }

    if ((*root)->data > data) {
        insert(&(*root)->left, data);
    } else if ((*root)->data < data) {
        insert(&(*root)->right, data);
    }
}

...  

void destruct(Node **root) {
    if (*root == NULL) {
        return;
    }
    destruct(&(*root)->left);
    destruct(&(*root)->right);
    delete *root;
    *root = NULL;
}

# 허상 포인터