Unique Pointer (std::unique_ptr) 정리
1. Unique Pointer란?
std::unique_ptr는 익스클루시브 오너십(Exclusive Ownership) 을 제공하는 스마트 포인터 입니다.
- 하나의 객체는 단 하나의 unique_ptr만 소유할 수 있습니다.
- 일반 포인터처럼 여러 개의 포인터가 같은 객체를 가리키는 것을 허용하지 않습니다.
- 이를 통해 객체의 소유권을 명확하게 관리하고 메모리 관련 버그를 줄일 수 있습니다.
일반 포인터의 문제:
Cat* cat = new Cat();
Cat* cat2 = cat;
위 코드에서는 여러 포인터가 하나의 객체를 가리킬 수 있습니다.
cat ──┐
├──> Cat Object
cat2 ──┘
이 구조에서는 누가 객체를 삭제해야 하는지 불명확함.
예를 들어 한쪽에서:
delete cat;
를 수행하면 다른 포인터는 이미 삭제된 객체를 가리키는 댕글링 포인터가 됩니다.
2. 일반 포인터의 문제점
여러 포인터가 하나의 객체를 공유 가능
예:
Cat* cat = new Cat();
Cat* cat1 = cat;
void func(Cat* ptr)
{
Cat* ptr2 = ptr;
}
메모리 구조:
Stack
cat
|
cat1
|
ptr
|
ptr2
|
v
Heap
Cat Object
하나의 객체를 여러 포인터가 가리킨다.
장점:
- 객체를 복사하지 않아 효율적
문제:
- 소유자가 불명확함
- 잘못된 delete 가능
- 메모리 릭 발생 가능
예:
void func(Cat* ptr)
{
delete ptr;
}
이렇게 하면:
- 객체는 이미 삭제됨
- 다른 포인터들은 삭제된 메모리를 가리킴
- 이중 삭제(double delete) 문제 발생 가능
3. unique_ptr 사용 방법
헤더:
#include <memory>
생성:
std::unique_ptr<Cat> catPtr = std::make_unique<Cat>();
unique_ptr은 내부적으로 객체의 생명주기를 관리한다.
스코프가 끝나면 자동으로:
- 객체 소멸자 호출
- 메모리 해제
가 수행된다.
따라서 직접:
delete
를 호출할 필요가 없다.
4. unique_ptr의 복사 금지
unique_ptr의 가장 중요한 특징:
객체의 소유권 복사를 허용하지 않는다.
예:
std::unique_ptr<Cat> cat1;
std::unique_ptr<Cat> cat2 = cat1;
컴파일 에러 발생.
이유:
cat1 ──┐
├──> Cat Object
cat2 ──┘
같은 객체를 두 개의 unique_ptr이 소유하는 상황을 막기 때문이다.
5. unique_ptr의 이동(move)
복사는 불가능하지만 소유권 이동(move) 은 가능하다.
std::unique_ptr<Cat> cat1 =
std::make_unique<Cat>();
std::unique_ptr<Cat> cat2 =
std::move(cat1);
결과:
이전:
cat1 ──> Cat Object
cat2
이후:
cat1
(null)
cat2 ──> Cat Object
소유권이 cat1에서 cat2로 이동한다.
즉:
- 기존 소유자는 더 이상 객체를 관리하지 않음
- 새로운 소유자가 객체를 관리
6. unique_ptr을 사용하는 대표적인 상황
클래스 멤버 변수로 포인터를 가지고 있어야 하는 경우
특히 다이나믹 폴리모피즘(Dynamic Polymorphism) 에서 많이 사용된다.
예:
class Animal
{
public:
virtual void speak();
};
class Cat : public Animal
{
};
class Dog : public Animal
{
};
동물원 클래스:
class Zoo
{
Animal* animal;
};
일반 포인터를 사용하면 문제가 발생한다.
필요한 작업:
- destructor 작성
- copy constructor 작성
- move constructor 작성
- assignment operator 작성
즉 Rule of 3/5를 직접 관리해야 한다.
7. unique_ptr을 이용한 개선
class Zoo
{
std::unique_ptr<Animal> animal;
};
이렇게 변경하면:
- 직접 delete 필요 없음
- destructor 작성 필요 없음
- 복사 문제 방지
- 객체 소유권 명확
객체 구조:
Zoo
m_animal(unique_ptr)
|
v
Cat Object
Zoo 객체가 사라지면:
- unique_ptr 소멸
- Cat 객체 자동 삭제
8. unique_ptr과 상속
unique_ptr은 다형성과 함께 사용할 수 있다.
예:
std::unique_ptr<Animal> animal;
animal = std::make_unique<Cat>();
가능한 이유:
- Cat은 Animal을 상속
- Animal 포인터가 Cat 객체를 가리킬 수 있음
- virtual destructor 필요
class Animal
{
public:
virtual ~Animal(){}
};
핵심 정리
| 특 징 | 내 용 |
| 소유 방식 | Exclusive Ownership |
| 소유자 수 | 1개 |
| 복사 | 불가능 |
| 이동 | 가능 (std::move) |
| 메모리 해제 | 자동 |
| 주요 목적 | 메모리 릭 방지 |
| 대표 사용처 | 클래스 멤버 포인터, 다형성 객체 관리 |
결론
std::unique_ptr는 객체의 소유권을 하나로 제한하여 안전한 메모리 관리를 가능하게 하는 스마트 포인터이다.
일반 포인터처럼 여러 곳에서 객체를 가리키는 구조를 막고, 객체의 생명주기를 소유자의 생명주기와 연결한다.
특히:
- 클래스 내부에서 동적으로 생성되는 객체 관리
- 상속 기반의 다형성 구현
- 명확한 객체 소유권 관리
상황에서 가장 기본적으로 고려하는 스마트 포인터이다.
다음 단계에서는 여러 개의 스마트 포인터가 하나의 객체를 공유할 수 있는 std::shared_ptr와 참조 카운팅, 그리고 순환 참조로 인한 메모리 릭 문제를 학습한다.
'Fundamental of CS > : : C++' 카테고리의 다른 글
| [Smart Pointer] Weak Pointer (0) | 2024.07.16 |
|---|---|
| [Smart Pointer] Shared Pointer (0) | 2024.07.16 |
| [Smart Pointer] Smart Pointer (0) | 2024.07.16 |
| [Smart Pointer] C++ SmartPtr (0) | 2024.07.16 |
| [Inheritance] C++ IO 상속 구조 정리 (0) | 2024.07.16 |