: 이미 해제된 메모리 영역를 계속해서 가리키고 있는 포인터를 말하는 것으로 유효하지 않은 메모리를 가리키고 있기 때문에 Segmentation fault가 발생할 수 있음
int* p = new int(3);
delete p;
*p = 10; // 정의되지 않은 동작 (Undefined Behavior)
delete 또는 delete[]를 사용하여 메모리를 해제한 후, 여전히 그 메모리를 가리키는 포인터가 남아있는 경우
int* DanglingPointer()
{
int local_val = 10;
return &local_val; // local_val은 함수가 끝나면 소멸됨
}
int main()
{
int* p = DanglingPointer();
*p = 5; // 정의되지 않은 동작 (Undefined Behavior)
return 0;
}
함수가 종료된 후에도 지역 변수를 가리키는 포인터가 남아있는 경우
class MyClass
{
public:
int value;
};
int main()
{
MyClass* obj = new MyClass();
int* p = &obj->value;
delete obj; // obj와 그 멤버 value는 더 이상 유효하지 않음
*p = 10; // 정의되지 않은 동작 (Undefined Behavior)
return 0;
}
객체가 소멸된 후, 그 객체의 멤버에 대한 포인터가 남아있는 경우
int* p = new int(5);
delete p;
p = nullptr; // p를 nullptr로 설정하여 더 이상 사용하지 않도록 함
메모리를 해제한 후 포인터를 nullptr로 설정하여, 해제된 메모리를 다시 참조하는 것을 방지함
#include <memory>
int main()
{
std::unique_ptr<int> p = std::make_unique<int>(3);
// 메모리는 자동으로 관리되고, 댕글링 포인터가 발생되지 않음
return 0;
}
C++ 이후, 스마트 포인터(std::unique_ptr, std::shared_ptr)를 사용하여 자동으로 메모리를 관리
#include <iostream>
class Resource
{
public:
Resource() {}
~Resource() {}
};
void useResource()
{
Resource res;
// res는 함수가 끝날 때 자동으로 소멸됨
}
int main()
{
useResource();
// Resource는 자동으로 해제됨
return 0;
}
객체의 수명을 명확히 관리하여, 소멸된 객체를 참조하지 않도록 함
ex. 객체의 소멸 후 그 객체를 참조하는 포인터를 사용하지 않도록 주의
💡RAII (Resource Acquisition Is Initialization) 원칙
: 객체의 생명 주기를 관리하여 자원을 할당하고 해제하는 것을 객체의 생성자와 소멸자에서 처리