모던 C++ : 스마트 포인터와 객체 생성

brewmaster
newworld-kim
Published in
4 min readDec 21, 2020

C++에서 객체를 생성하기 위한 방법은 다양하다. 주요한 방법들을 알아보고 어떤 장단점들이 있는지 간략히 알아보자. 아래 내용을 잘 이해하면 모던 C++ 디자인 패턴을 이해하는데 도움이 된다.

스택에 할당하기

스택(Stack) 메모리를 할당 받아 객체를 생성하는 방법이다. 정적 메모리 할당의 방법 중 하나이며, 메모리의 크기가 하드 코딩되어 있기 때문에 프로그램이 실행될 때 이미 해당 메모리의 크기가 결정되게 된다.
(메모리에 관한 내용은 별도 포스팅에서 다룰 예정이다)

스택에 생성된 객체는 스코프를 벗어날 때 해당 객체의 소멸자가 호출되어 자동으로 소멸된다. (명시적으로 소멸시킬 수도 있다.) 덕분에 해제에 대한 메모리 누수와 같은 문제를 신경쓰지 않아도 되지만, 메모리 크기가 이미 정해져있기 때문에 런타임 메모리 크기를 조절할 수 없게 된다.

스택과 힙

아래 예의 객체처럼 스코프 내에서 선언하여 스택에 할당한다.

스택에 할당하기

힙에 할당하기

힙(Heap) 메모리를 할당 받아 객체를 생성하는 방법이다. 스택에 할당하는 방법과 반대로, 동적 메모리 할당의 방법 중 하나다. 프로그램의 실행 시간에 크기를 결정하게 된다.

가장 기본적인 원시 포인터를 이용하여 객체를 생성하면 힙에 객체를 할당할 수 있다. 그러나, 힙에 할당된 객체는 스택에 할당된 객체처럼 자동으로 소멸되지 않는다. 때문에, 객체를 사용 후 메모리 해제를 해야 메모리 누수와 같은 문제를 피할 수 있다.

힙에 할당하기

원시 포인터를 통한 객체 생성하기 이전에, 정말로 이 방법 밖에 없는지 다시 한 번 고민해보자. 객체 소멸 등에 대해 우리를 괴롭게하지 않을 더 멋진 방법이 있지 않을까?

스마트 포인터로 객체 생성하기

스택과 힙 메모리를 할당 받아 객체를 생성하는 방법을 간략히 소개했다. 이번에는 스택의 장점과 힙의 장점을 가지고 있는 스마트 포인터로 객체 생성하는 방법을 알아보자.

우선, 일반적인 스마트 포인터 객체를 선언하면 객체는 스택 메모리를 할당 받아 생성되게 된다. 그러나 객체 내부적으로 포인터를 지니고 있어, 동적으로 메모리를 할당 받을 수 있다. 또한, 생성자와 소멸자를 포함하고 있어서 메모리 할당과 해제가 객체의 선언과 소멸 시점에서 이루어진다. 덕분에 메모리 누수에 대한 걱정을 덜 수 있게 되었다!

이제 C++에서 제공하는 스탠다드 스마트 포인터 3가지를 소개한다.

unique_ptr

unique_ptr 는 동적으로 할당된 객체의 포인터를 관리한다. 또한, 참조하는 객체를 관리하는데, 해당 포인터에 할당된 메모리를 더 이상 참조하는 곳이 없을때 자동으로 소멸한다. 소유권을 이전(move)할 수는 있지만, 복사(copy)나 대입(assign)을 할 수는 없다.

unique_ptr 예

shared_ptr

shared_ptrunique_ptr 처럼 동적으로 할당된 객체의 포인터를 관리하지만, 소유권 이전 뿐만 아니라, 복사나 대입이 가능한 스마트포인터다. 해당 포인터에 할당된 메모리를 더 이상 참조하는 곳이 없을때는 자동으로 소멸한다.

shared_ptr 예

weak_ptr

weak_ptrshared_ptr 을 간접적으로 참조한다. 동적으로 할당된 객체의 포인터를 직접적으로 소유할 수 없다. (나중에 따로 소개하겠지만) shared_ptr 은 순환참조 문제를 가질 수 있는데, 이 경우 weak_ptr 로 해결할 수 있다.

weak_ptr 예

스택과 힙 메모리를 할당 받아 객체를 생성하는 방법과 C++에서 제공되는 스마트 포인터 몇가지를 가볍게 익혀보았다. 위 개념은 다른 모던 C++ 포스팅에서 다뤄질 내용들을 이해하는데 필수적인 개념이다.

--

--