| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
Tags
- Lock-free Stack
- Behavior Design Pattern
- 비트마스킹
- 최소 공통 조상
- localstorage
- trie
- ccw 알고리즘
- Binary Lifting
- 그래프 탐색
- SCC
- DP
- 자바스크립트
- 게임 서버 아키텍처
- R 그래프
- Prisma
- 2-SAT
- 비트필드를 이용한 dp
- 분리 집합
- Strongly Connected Component
- 이분 탐색
- map
- 벨만-포드
- JavaScript
- Spin Lock
- PROJECT
- Github
- Express.js
- LCA
- 강한 연결 요소
- 트라이
Archives
- Today
- Total
dh_0e
[C++] Smart Pointer 본문
Smart Pointer 개요
- 기존 new, delete를 사용할 때 발생하는 여러 메모리 문제들(memory leak, nullptr issue, Dangling Pointer)을 방지하기 위해 만들어짐
- Java, C#에서는 Garbage Collector를 사용하여 이 문제를 해결하여 개발자의 생산성을 올려주었지만, 컴퓨터에 부하가 더해져 속도가 느려짐
- C++ 11 이후 추가되었으며, <memory> 헤더 파일을 선언하여 사용 가능
- 클래스로 만들어졌으며, 생산자에 포인터를 할당하고, 소멸자에서 이를 delete 해주면서 객체가 만들어질 때 메모리 할당을, 소멸할 때 메모리 해제를 자동으로 해주게끔 만들어 메모리 누수를 방지함
template<typename T>
class smart_pointer{
public:
smart_pointer(T* p): ptr(p) {}
~smart_pointer(){
delete ptr;
}
// 복사 금지: Double Free 방지
smart_pointer(const smart_pointer&) = delete;
smart_pointer& operator=(const smart_pointer&) = delete;
// 연산자 오버로딩
T& operator*() const { return *ptr; }
T* operator->() const { return ptr; }
// 결과값이 여전히 포인터 타입이라면, 컴파일러는 거기에 다시 ->를 자동으로 붙여서 멤버에 접근
private:
T* ptr;
}
- unique_ptr을 class로 직접 구현해 보면 위와 같은 형태로 이루어져 있음
- 실제 코드는 훨씬 복잡하며 위 코드는 new로 할당한 단일 객체만 관리할 수 있고, new[]로 할당한 배열은 불가능
- smart_pointer<T[]> 형태에 대한 코드를 추가해야 함
- delete를 통한 수동 해제가 불가능함
- STL이라 원형은 std:: 생략 필
Smart Pointer 종류 및 사용법
1. shared_ptr
- 여러 포인터가 한 객체를 참조하여 관리할 수 있는 스마트 포인터
- 해당 값을 참조하고 있는 포인터가 몇 개인지 저장하고 있는 참조 횟수(reference count)가 있음
- 선언
- shared_ptr<T> ptr(new T(value)); // 메모리 할당 2번
- shared_ptr<T> ptr = make_shared<T>(value); // 메모리 할당 1번
- 속도가 달라서 make_shared를 사용하는 게 좋음
- 선언

- 참조 횟수(reference count)
- ptr.use_count(); // main()이 종료되거나 참조 카운트가 0이 되어야 소멸자 작동
#include <iostream>
#include <memory>
using namespace std;
int main() {
shared_ptr<int> ptr=make_shared<int>(10);
printf("ptr: %d\n",*ptr);
printf("ref count: %d\n", ptr.use_count());
auto ptr2=ptr;
(*ptr2)++;
printf("ptr: %d\n",*ptr);
printf("ptr2: %d\n",*ptr2);
printf("ref count: %d\n", ptr2.use_count());
auto ptr3=ptr2;
(*ptr3)++;
printf("ptr: %d\n",*ptr);
printf("ptr2: %d\n",*ptr2);
printf("ptr3: %d\n",*ptr3);
printf("ref count: %d\n", ptr3.use_count());
return 0;
}

2. unique_ptr
- 하나의 포인터만이 객체를 참조하여 관리할 수 있는 스마트 포인터
- reference count(참조 횟수)가 1로 고정된 shared_ptr
- 복사 생성자를 지원하지 않으며, move() 함수를 통한 전달만 가능함
- 선언
- unique_ptr<T> ptr(new T(value));
- unique_ptr<T> ptr = make_unique<T>(value);
- make_unique는 속도 차이는 거의 없지만 가독성과 안정성 때문에 make_unique를 많이 씀
#include <iostream>
#include <memory>
using namespace std;
int main() {
unique_ptr<int> ptr=make_unique<int>(10);
printf("ptr: %d\n",*ptr);
auto ptr2=ptr; // error
return 0;
}
3. weak_ptr
- 약한 참조를 의미하며, shared_ptr를 사용할 때 순환 참조와 같은 문제에 대처하는 데 도움을 줌
- 순환 참조: 객체 안에 서로의 포인터를 잡고 있어서 서로가 끝나기 전까지 소멸하지 않는 데드락과 유사한 현상을 일으킴
순환 참조 예시
#include <iostream>
#include <memory>
#include <string>
class Room; // 전방 선언
class Player {
public:
std::shared_ptr<Room> currentRoom; // 플레이어가 속한 방
~Player() { std::cout << "Player 소멸!\n"; }
};
class Room {
public:
std::shared_ptr<Player> owner; // 방의 주인인 플레이어
~Room() { std::cout << "Room 소멸!\n"; }
};
int main() {
{
auto p1 = std::make_shared<Player>();
auto r1 = std::make_shared<Room>();
// 서로를 가리킴 (순환 참조 발생)
p1->currentRoom = r1;
r1->owner = p1;
}
// 블록을 벗어나도 "소멸!" 메시지가 뜨지 않음 -> 메모리 누수 발생!
std::cout << "블록 종료\n";
return 0;
}
- weak_ptr은 shared_ptr과 유사하지만 가리키는 객체의 수명에 영향을 주지 않는 약한 참조를 하여 순환 참조를 피함
class Room {
public:
// shared_ptr 대신 weak_ptr 사용!
std::weak_ptr<Player> owner;
~Room() { std::cout << "Room 소멸!\n"; }
};
- 위와 같이 owner를 weak_ptr로 바꾸면 r1->owner = p1;을 해도 p1의 참조 횟수가 올라가지 않아 블록이 끝날 때 정상적으로 소멸함

- weak_ptr로 실제 객체를 쓰기 전에, 객체가 해제됐는지 알 수 없기 때문에 lock() 함수를 호출해서 객체가 아직 살아있는지 확인해야 함
'C++' 카테고리의 다른 글
| [C++] 콜백(Callback) 함수, using & typedef (0) | 2026.02.11 |
|---|---|
| [C++] lambda, 타입 추론(auto), 일반화 함수(template), Singleton in C++ (3) | 2025.08.05 |
| [C++] memset, isupper/islower (0) | 2025.02.13 |
| [C++] stringstream (2) | 2024.07.22 |
| [C++] max_element, min_element, find (0) | 2024.07.12 |