[C++] 스마트 포인터

jaehyeonLee·2024년 12월 30일

스마트 포인터

스마트 포인터는 헤더 파일의 std 네임스페이스에서 정의가된다.
RAII에서 매우 중요하다고 하는데 먼저 RaII 부터 알아보도록 하겠다.

RAII 와 메모리누수

자세한 내용 : https://learn.microsoft.com/ko-kr/cpp/cpp/object-lifetime-and-resource-management-modern-cpp?view=msvc-170

RAII: Resource Acquisition Is Initialization : 리소스 획득은 초기화이다

C++에는 프로그램이 실행 될때 heap 메모리 및 기타 리소스를 해제하는 내부 프로세스인 Garbage Collector 가 없다 c++ 프로그램은 획득한 모든 리소스를 운영체제로 반환하는 역할을 담당하는데 사용하지 않는 리소스를 해제하지 못한경우 '메모리 누수 '라고 한다 . 프로세스가 종료 될때까지 유출 된 리소스는 다른 프로그램에서 사용할수가 없다.

C++는 스택에 개체를 선언하여 힙메모리를 최대한 사용하지 않도록 방지한다. 리소스가 스택에 비해 너무 크면 개체가 소유해야한다. 개체가 초기화 되면 소유하는 리소를 획득한다. 그다음 개체는 소멸자에서 리소를 해제한다. 소유 개체 자체는 스택에 선언된다 .이렇게 개체가 리소스를 소유한다는 원칙을 "리소스 획득은 초기화이다" 혹은 RAII라고 한다

class widget
{
private:
  int* data;
public:
  widget(const int size) { data = new int[size]; } // new 사용 
  ~widget() { delete[] data; } // delete
  void do_something() {}
};

void functionUsingWidget() {
  widget w(1000000);  
                      
  w.do_something();

} //w 및 w.data에 대한 자동 파기 및 할당 해제

보통 c++에서 동적할당을 할때 new 를 사용할것이다 . 이때 new를 사용하여서 힙 메모리에서 메모리를 할당받을거다 현재 예제에서는 메모리 리소를 소유하므로 소멸자의 코드가 있어야 메모리를 삭제할수가있다. 해제를 할때 delete를 해주어 메모리를 해제해줄거다 이렇게 해당 소멸자의 코드가 있어야 메모리를 삭제해줄수있다. 만약 소멸자의 코드가 없이 넘어가면 이때 메모리의 누수가 일어나게될거다

스마트 포인터를 사용하는 더 좋은방법이 있다. 스마트 포인터는 소유하는 메모리의 할당 및 삭제를 처리한다. 스마트포인터를 사용하면 클래스에서 명시적 소멸자가 필요가 없게 된다

#include <memory>
class widget
{
private:
  std::unique_ptr<int[]> data;
public:
  widget(const int size) { data = std::make_unique<int[]>(size); }
  void do_something() {}
};

void functionUsingWidget() {
  widget w(1000000);  // lifetime automatically tied to enclosing scope
                      // constructs w, including the w.data gadget member
  // ...
  w.do_something();
  // ...
} // automatic destruction and deallocation for w and w.data

메모리 할당에 스마트 포인터를 사용하면 메모리 누수 가능성이 제거가 될수 있다.

스마트 포인터의 종류

unique_ptr
unique_ptr은 c++ 표준 라이브러리에서 제공하는 스마트 포인터로 단일 소유권의 개념을 구현한다.
이는 특정 리소스에 대한 소유권을 오직 한 '객체'만 가질 수 있다는것을 의미한다.
소유권을 다른 unique_ptr로 '이동'은 가능하나 복사 및 공유는 불가능하다 이러한특징으로 명시적인 소유권관리와 안전한 리소스 해제를 보장한다

구조: 내부적으로 단순히 하나의 포인터만 저장하며 크기가 작고 메모리접근이 빠름

shared_ptr
참조횟수가 계산되는 스마트 포인터이다 . 원시 포인터 하나를 여러소유자에게 할당하려고 할경우에 사용을 한다 리소스를 소유한 모든 shared_ptr 객체가 범위를 벗어나거나 소유권을 포기할때 리소스가 자동으로 삭제가 된다.

참조횟수 관리 : 내부적으로 참조 횟수를 유지하며 새로운 shared_ptr 이 생성이 될때 참조횟수가 증가하고 소멸할때 감소한다. 참조횟수가 0이되면 관리중인 resource를 해제한다

구조: 크기는 두개의 포인터로 구성이된다.
하나는 resource용이고 다른하나는 참조횟수가 포함된 공유제어 블록용이다

weak_ptr
shared_ptr과 함께 사용할 수 있는 특별한 경우의 스마트포인터이다 .
weak_ptr은 하나이상의 shared_ptr 인스턴스가 소유하는 개체에 대한 액세스를 제공하지만 참조수 계산에는 참가하지 않는다

순환참조 방지역할을해준다 .
예를 들어 두개의 shared_ptr가 서로를 참조하면 참조횟수가 0이 되지않아 메모리 누수가 발생이 가능한다 weak_ptr은 이러한 문제를 해결해줄수가있다.

이렇게 스마트 포인터에대해서 간단히 개념만 알아보았는데 이후 unique_ptr , shared_ptr , weak_ptr 지금 현재 DirectX11 공부중에서 나오는 ComPtr 등을 자세히 다루어보도록하겠다

profile
이재현의 필기노트

0개의 댓글