읽은 기록/Effective Modern C++

[CH.4] Smart Pointers

silencecolor 2026. 4. 5. 20:45
반응형

스마트 포인터에 관한 내용을 이야기하는 4장이다.

 


 

생포인터(Raw Pointer)를 사용하기 힘든 이유

1. 가리키는 대상의 모호함

- 포인터 선언만으로는 단 하나의 객체를 가리키는지, 아니면 배열 전체를 가리키는지 알 수 없음

2. 소유권의 불분명함

- 사용을 마친 후 가리키는 대상을 파괴(destroy)해야 하는지 알 수 없음. 

- 포인터가 그 대상의 '소유권'을 가졌는지 여부는 선언부만으로는 알 수 없음

3. 파괴 방법의 불확실성

- 파괴해야 한다면 어떻게 해야하는지 명확하지 않음

- delete를 써야 하는지, 별도의 전용 파괴 함수를 호출해야 하는지 등

4. delete와 delete[]

- 만약 delete를 쓰는게 맞더라도, 단일 객체용(delete)을 써야 할지, 배열용(delete[])을 써야할지 모름.

- 근데 잘못쓰면 미정의 동작(Undefined Behavior)이 발생함

5. 모든 경로에서의 해제 보장

- 소유권과 파괴 방법을 알았다 해도, 예외 경로를 포함한 모든 실행 경로에서 정확히 단 한번만 파괴되도록 보장하기가 매우 어려움.

- 해제를 놓치면 자원 누수가 발생하고, 두번 해제하면 미정의 동작(Undefined Behavior)이 발생함.

6. 대상을 잃은 포인터

- 포인터가 가리키던 대상이 이미 파괴되었는데 여전히 그 메모리 주소를 가리키고 있는지 확인할 방법이 없음.

 


 

생포인터는 강력한 도구이지만, 그만큼 제대로 사용하지 않았을 때(혹은 못했을 때)의 위험성이 크다.

 

스마트포인터는 이런 문제를 해결하기 위한 방법이다.

스마트포인터는 생 포인터를 감싸는 래퍼(Wrapper)로, 생 포인터 처럼 동작하면서도 생 포인터가 줄 수 있는 위험을 피할 수 있게 설계되었다. 그러니 생포인터 보다는 스마트 포인터를 써야 한다.

 


 

C++11에서는 4개의 스마트포인터가 있다.

- std::auto_ptr

- std::unique_ptr

- std::shared_ptr

- std::weak_ptr

 

이들은 모두 동적으로 할당된 객체의 수명을 관리하여 자원 누수를 방지하기 위해 설계되었다.

 


 

auto_ptr은 C++98에서 남겨진, 이제는 더 이상 사용되지 않는(deprecated) 유산이다.

당시 unique_ptr를 만들려던 시도였지만, 이동 의미론(Move Sementics)이 없었기에 복사 연산을 이동 연산처럼 사용하도록 우회했다.

그 결과 복사를 했는데 원본이 null이 되는 문제가 발생했고, STL 컨테이너에 넣을 수 없다는 등의 제약이 심했다.

 

unique_ptr은 auto_ptr이 하던 모든 동작을 더 효율적으로 수행하면서 복사의 의미를 왜곡하지 않는다.

모든 면에서 auto_ptr보다 낫기에 C++98 컴파일러를 사용해야 하는 상황이 아니라면 unique_ptr을 써야만 한다.

 


 

CH4에서 다룰 내용은, 단순히 스마트포인터에 대한 설명은 아니다.

스마트포인터의 API정보는 어디서나 찾아볼 수 있기 때문이다. 그렇기에 이 책에선 일반적인 API 개요에 빠져있는, 하지만 주목할 만한 사용 사례(Use Cases), 런타임 비용 분석 등에 집중할 것이다.

이런 정보를 알고 스마트포인터를 효과적으로 사용하는 것은 그냥 단순히 스마트포인터를 사용하는 것과 큰 차이가 있을 것이다.

반응형