스마트포인터
: RAII가 사용되는 포인터 (정확한 정의는 아니지만 이렇게 이해하면 편함)
RAII
: Resource Acquisition Is Initialization
> GC가 없는 C++에서 메모리누수(memory leak. 힙에 동적할당된 데이터가 삭제되지 않고 남아있는 것. delete하는 것을 잊어버리면 발생할 수 있다)를 방지하기 위해 RAII라는 디자인패턴을 사용할 수 있다.
RAII는 쉽게 말해 어떤 포인터가 Scope 혹은 선언된 함수 범위를 벗어났을 때 자동으로 어떤 일을 처리하게끔 하는 기능을 제공하는 것을 말한다. 이 "자동 실행 기능"은 메모리 해제가 될 수도 있고, 다양한 것들이 될 수 있다.
unique_ptr
: Exclusive Ownership (즉 하나의 객체를 가리키는 포인터는 오직 하나만 존재할 수 있다.)
> 어떤 객체를 a라는 unique_ptr로 가리킨 후 다른 포인터(어떤 종류든)로 같은 객체를 가리키려고 시도하면 컴파일 에러가 발생한다.
> unique_ptr는 포인터가 선언된 scope(중괄호) 혹은 함수를 벗어나면 자동으로 포인터가 가리키는 오브젝트를 해제해준다. (포인터만 지우는 게 아니라 아예 소멸자를 호출해준다)
shared_ptr
: Nonexclusive Ownership
> 어떤 객체는 a라는 shared_ptr가 가리킬 수 있으며, b, c, 등 다른 shared_ptr도 같은 객체를 가리킬 수 있다.
이때 해당 객체가 총 몇번 reference되고 있는지를 구할 수 있다. (Reference Count)
여기서 a.use_count()나 b.use_count()가 같은 값을 반환한다는 점에 유의할 것. 즉 같은 객체를 가리킨다면 서로 다른 shared_ptr라도 같은 reference count를 가진다.
> unique_ptr와 마찬가지로 포인터가 선언된 scope(중괄호) 혹은 함수를 벗어나면 자동으로 포인터가 가리키는 오브젝트를 해제해준다. (포인터만 지우는 게 아니라 아예 소멸자를 호출해준다)
또한 이 Reference Count가 0이 되면 해당 포인터(들)가 가리키는 객체를 자동으로 해제해준다.
그러나 C++는 파이썬, C#등과 달리 컴파일러가 자체적으로 Reference Count를 해주는 것이 아니기 때문에, shared_ptr를 사용했음에도 자동으로 소멸되지 않고 메모리 누수가 발생할 수 있다.
ex.
GameMap* gamemap = new GameMap();
Engine* engine = new Engine();
이라고 하자.
GameMap::shared_ptr<Engine> m_engine;
m_engine = engine; 이고
동시에
Engine::shared_ptr<GameMap> m_gamemap;
m_gamemap = gamemap;
이라면
gamemap과 engine의 reference count는 아무리 낮아져도 절대 1 아래로 내려가지 않는다.
서로가 서로를 reference하고 있기 때문이다.
이러한 상황에서는 스마트포인터를 사용하고 있음에도 만약 delete를 잊어버린다면 메모리가 자동으로 해제되지 않아 메모리 누수가 발생할 수 있다.
(파이썬 등에서는 이러한 상황을 컴파일러/인터프리터가 알아서 해결해서 둘다 삭제해준다. 이때 Mark and Sweep과 같은 방식이 사용된다.)
'lang > c++' 카테고리의 다른 글
std::iterator, std::advance (0) | 2022.05.18 |
---|---|
Bitwise operator (C/C++) (0) | 2021.08.20 |
stl::queue 초기화 (0) | 2021.04.02 |
ceil floor round (#include <cmath>) (0) | 2021.04.02 |
std::set의 iteration (0) | 2021.03.30 |