반응형
unique_ptr 객체는 스택(stack)에 살아요
스마트 포인터인 unique_ptr로 생성한 객체 자체는 스택에 존재한다. 스택에 존재하면서 힙에 할당된 메모리를 관리한다. 이를 C++에서는 RAII(Resource Acquisition Is Initialization) 패턴이라고 부른다.
실제 예제 코드
class MyClass
{
public:
MyClass() { std::cout << "자원 생성\n"; }
~MyClass() { std::cout << "자원 소멸\n"; }
};
void main()
{
{
std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>();
} // <- 이 범위를 벗어나며 소멸함
// 이때 내부의 ptr도 자동으로 delete함
}
- std::unique_ptr<MyClass> ptr 변수가 스택에 생성된다.
- std::make_unique가 힙에 메모리를 할당하고 그 주소를 ptr 변수에 담는다.
- 이제 스택에 있는 ptr은 힙에 있는 객체의 관리자가 된다.
- 블록이 끝나는 순간 스택에 있던 ptr 변수가 메모리에서 제거된다. (소멸자 호출)
- 이때 ptr이 관리하고 있던 힙 메모리도 같이 정리된다. (ptr의 죽음의 메아리 효과라고 보면 된다.)
생 포인터(Raw Pointer)를 쓰는 경우
std::unique_ptr을 쓰지 않고 이전 방식인 생 포인터를 쓴다면 어떨까?
{
MyClass* ptr = new MyClass(); // ptr은 그냥 주소값일 뿐인 '단순 변수'
// ... 만약 여기서 return이나 예외가 발생해서 아래 delete에 못 가면?
delete ptr; // 이 코드를 실행해야만 힙이 비워짐
}
이에 반해 unique_ptr은 "스택 변수는 블록이 끝나면 무조건 파괴된다"라는 운영체제의 철칙을 이용하기 때문에 개발자가 깜빡해도 메모리가 안전하게 회수된다.
unique_ptr의 장점
- 유일한 통제권(Exclusive Ownership)
- 추적의 용이성: 특정 객체의 상태가 변했다면, 범인은 오직 unique_ptr을 가진 주체뿐이다.
- 복사 실수 방지: 함수에 인자로 넘길 때 실수로 복사해서 원본이 언제 지워질지 모르게 되는 상황을 컴파일러 단계에서 원천적으로 차단한다.
- 객체 생명주기와의 동기화(RAII)
- 자동 파괴: delete를 명시적으로 적지 않아도 객체가 파괴되면 같이 해제됩니다. 잊어버릴 가능성 자체가 사라지게 된다.
- 예외 안정성(Exception Safety): 코드가 실행되다가 중간에 에러(Exception)가 발생해서 함수가 갑자기 종료되더라도, 스택에 쌓여있던 unique_ptr은 소멸자를 호출하여 힙 메모리를 깨끗하게 제거한다.
unique_ptr은 언제 사용해야하는가?
- 객체의 크기가 너무 클 때(Stack Overflow 방지)
- 다형성(Polymorphism)을 활용해야 할 때
- 객체의 생명 주기를 자유롭게 조절해야 할 때(Life-cycle)
상황에 맞게 선택하기
- 객체가 작고, 해당 블록 안에서 사용하고 버릴 경우 > 그냥 객체(스택 변수)를 사용하자.
- 객체가 크거나, 상속 구조가 필요하거나, 소유권을 주고 받아야할 때 > 스마트 포인터 unique_ptr을 사용하자.
- 여러 곳에서 하나의 객체를 동시에 소유하고 참조해야 할때 > 스마트 포인터 shared_ptr을 사용하자.
정리하자면
- unique_ptr은 값의 문법(Value Semantics)으로 참조(Reference)를 관리한다.
- 스택처럼 변수가 선언된 블록이 끝나면 자동으로 정리됨 (Scope-based)
- 포인터처럼 실제 데이터는 힙에 있어서 크기 제한이 없고, 다형성을 활용할 수 있음
- 스택 변수처럼 쓰면서 동시에 힙의 장점을 가져가는 말 그대로 아주 똑똑한 포인터
같이 읽으면 좋은 글
메모리 구조(Memory Structure)에 대해서
메모리 구조우리가 exe 파일을 실행하면 운영체제는 프로그램에 정의된 명령어(코드)를 바탕으로 메모리에 프로세스를 적재(Load)한다. 그리고 해당 프로세스를 위한 Code, Data, Heap, Stack 영역이 생
jettstream.tistory.com
'프로그래밍 > C++' 카테고리의 다른 글
| unique_ptr vs shared_ptr 차이는 무엇인가? (0) | 2026.01.03 |
|---|---|
| C++ Erase-remove 관용구란 무엇인가? (0) | 2025.12.28 |
| emplace() vs emplace_back()의 차이점 알아보기 (0) | 2025.12.22 |
| C++ emplace_back()을 무조건 권장하지 않는 이유는? (0) | 2025.12.22 |
| C++ 기본 타입은 왜 std::move()로 이동되지 않는가? (0) | 2025.12.20 |
댓글