728x90
학습목표
- C++의 전통적인 포인터(new/ delete)가 왜 위험한지 이해한다.
- RAII(Resource Acquisition Is Initialization)라는 핵심 원칙을 설명할 수 있다.
- 소유권을 독점하는 std::unique_ptr의 특징과 사용법을 익힌다.
- 소유권을 공유하는 std::shared_ptr의 특징과 사용법을 익힌다.
핵심 키워드
- 메모리 누수(memory leak)
- RAII(Resource Acquisition Is Initialization)
- 소유권(Ownership)
- std::unique_ptr
- std::shared_ptr
- std::make_unique/std::make_shared
1.문제
c++에서 동적할당한 메모리는 반드시 해제해줘야한다. 해제를 하지 못하면 그 메모리는 누수가 일어난다.
2. 해결
RAII (Resource Acquisition Is Initialization)패턴
- 자원을 획득하는 시점은, 그 자원을 관리할 ‘객채’의 ‘생성 시점’과 일치해야 한다.
메모리(자원)을 new로 직접 다루지 말고, 메모리를 관리하는 객체(스마트 포인터)를 만들어서 그 객체에게 관리를 맡기자는 것.
객체는 자기가 사라질 때소멸자가 자동으로 호출되면서 delete를 처리하도록 일을 수행한다.
3. 사용법
- 소유권 독점: std::unique_ptr
- unique_ptr은 이름 그대로 ‘유일한’ 소유권을 가진다. 복사는 불가능하고, 소유권을 다른 unique_ptr에게 이동시키는 것만 가능하다.
- 가볍고 빨라서 기본적으로 사용하는 스마트 포인터이다.
#include <memory> // 스마트 포인터를 사용하려면 꼭 포함해야 한다. void processPlayer_safe() { //이렇게 만들면 Player 객체의 소유권은 p가 가지게 된다. //std::make_unique를 쓰는 것이 가장 안전하고 좋은 방법이다. std::unique_ptr<Player> p = std::make_unique<Player>(); p->doSomething(); } // 함수가 끝나면 p가 사라지면서, 자기가 가리키던 Player 메모리를 자동으로 해제한다. - 소유권 공유:std::shared_ptr
- 공유라는 이름처럼, 하나의 메모리를 여러 shared_ptr이 함께 가리키며 공동으로 소유할 수 있다.
- 내부적으로 참조 카운트(Reference Count)라는 걸 가지고 있어서, 자신을 가리키는 shared_ptr이 몇 개인지 세고 있다.
- 새로운 shared_ptr가 같은 메모리를 가리키면 참조 카운트가 1증가한다.
- hared_ptr가 사라지면(스코프를 벗어나거나 다른 값을 할당받으면) 참조 카운트가 1 감소한다.
- 참조 카운트가 0이 되는 바로 그 순간, 마지막 남은 shared_ptr가 메모리를 delete 해준다.
- MMORPG에서 한 명의 플레이어가 파티 목록에도 있고, 공격대 목록에도 있을 때처럼 여러 곳에서 동일한 객체를 참조해야 할 때 유용하다.
#include <memory> #include <vector> //플레이어를 가리키는 포인터를 담을 리스트 std::vector<std::shared_ptr<Player>> party_list; std::vector<std::shared_ptr<Player>> raid_list; void managePlayer() { //플레이어를 만들고 p1이 소유(참조 카운트1) std::shared_ptr<Player> p1 = std::make_shared<Player>(); //파티리스트에 p1을 복사. 이제 p1과 list의 원소가 함께 소유(참조 카운트2) party_list.push_back(p1); //레이드리스트에도 p1을 복사(참조 카운트3) raid_list.push_back(p1); } // 함수가 끝나면 p1은 사라지지만, // 아직 list들이 객체를 가리키고 있으므로 참조 카운트는 2가되고 메모리는 해제되지 않는다.
728x90
'언어 > C++' 카테고리의 다른 글
| 클래스(Class) (0) | 2024.11.26 |
|---|---|
| 구조체(Struct) (0) | 2024.11.24 |
| 참조자(Reference) (0) | 2024.11.24 |
| 인라인(inline) 함수 (0) | 2024.11.24 |
| Call by Value/Call by Reference (0) | 2024.11.24 |