내가 c++을 처음 접하게 된 건 대부분의 컴퓨터 전공 학생들이 그렇듯이 학부 시절에 객체 지향 프로그래밍 수업을 들으면서였다.
학교마다 C++로 객체 지향을 공부하는 학교도 있고 Java로 객체 지향을 공부하는 학교도 있었지만, 모교에서는 C++로 수업을 했었다.
그 후로 PS를 했었고, 당연히 (개인적으로) 가장 좋은 언어는 C/C++이라고 생각했기 때문에 다른 그대로 사용을 했고, 학부를 졸업할 정도가 되었을 때, 1년 정도 머신러닝/딥러닝을 공부하면서 Python을 공부하게 되었다.
그래서 처음에 입사를 하고 어떤 언어를 사용하냐는 질문을 받았을 때, C++/Python이 메인 언어이고, Java나 다른 메이저한 스크립트 언어는 읽을 정도(?)만 된다고 대답을 했었다.
하지만, 정말 내 생각일 뿐이었다...ㅎㅎ
학부에서 공부했던 C++은 최근에 현업에서 사용하는 내용들을 충분히 반영하고 있지 못했기 때문에 처음에 프로젝트 코드를 열어보고.. 아무 생각이 나지 않았다. (아무 생각이 없기 때문입니다.)
그래서 Modern C++을 공부해야 겠다는 생각이 들었다.
일단 그래서 언제나 그랬듯이 책부터 사고,
생각을 해보기로 했다.
역시나, 책에서 내가 아는 내용보다 모르는 내용들이 더 많았다.
대부분의 학부를 졸업한 많은 개발자들이 나랑 비슷한 상태가 아닐까 하는 생각이 들었다.
오래되고, 코테를 보기 위한 정도의 C++
그래서, 언제나 그랬듯이 모르는 것에 대한 해답은 공부하는 것 뿐..!!
이 정도 깊이로 C++을 할 줄 안다고 했던 내가 부끄러워 지네요 ㅎㅎ
처음 주제를 smart pointer로 잡은 이유는, 내가 지금 정적 분석으로 defect을 처리하는 일을 하고 있는데 shared_ptr
가 대체 무슨 말인지를 모르겠어서 아무고토 못하고 있기 때문이다.
우선, smart pointer를 얘기하기 전에 간단하게 C++의 메모리 관리에 대한 얘기를 간단하게 해보자.
C++에서는 new
키워드를 사용하여 동적 할당한 메모리는 delete
를 사용하여 해제해야 한다.
사실 이게 간단하게 new
, delete
을 할 때는 문제가 안되는데, 프로젝트가 복잡해지고 parameter로 포인터를 주고 받고 하다보면 할당한 메모리를 누가 마지막에 쓰고, 해제해야 하는지 찾기가 어려울 때가 많다.
이 말은 곧, memory leak이 일어날 가능성이 많다는 말이 되겠다.
이 memory leak 문제는 리소스가 적은 환경에서는 더욱 critical한 문제가 될 수 있다.
여기서 smart pointer라는 개념이 등장한다.
smart pointer는 기존의 pointer 개념처럼 사용하는 class template으로 이해할 수 있다.
내가 이해한 개념으로는, 실제 리소스를 가리키는 pointer는 따로 존재하고 이 메모리 할당과 소유권에 대한 부분을 class template으로 만들어서 감싸는 느낌이다.
new
키워드를 사용해서 raw pointer가 실제 메모리를 가리키도록 하고 smart pointer에 넣어주면 destructor가 delete
키워드를 사용해서 메모리를 정상적으로 해제한다.
C++11 부터는 아래의 키워드를 사용한다고 한다.
unique_ptr
shared_ptr
weak_ptr
unique_ptr
하나의 smart pointer만 객체를 소유할 수 있는 소유권 개념을 도입한 것이다.
unique_ptr
에서 소유권은 move만 가능하고 copy는 되지 않는다.
(정말 당연하게도 copy를 하게 되면 유일하게 소유할 수 없기 때문이다!)
make_unique()
를 사용하면 unique_ptr
를 생성할 수 있다.(C++14 이상)
get()
메서드를 사용하면 내부 포인터(아까 처음에 smart pointer에 넣어줬던 그 포인터)에 직접 접근할 수 있다.
만약에, 어떤 함수가 smart pointer가 아니라 (우리가 알고 있던 그) pointer를 사용하는 함수라면 get()
메서드를 사용하여 넘겨줄 수 있다.
reset()
메서드를 사용하면 unique_ptr에 할당되어 있던 pointer를 해제하고, parameter로 다른 pointer를 넣어주면 그 pointer로 변경도 가능하다.
release()
메서드를 사용하면 unique_ptr의 내부 포인터를 return
하고 관계를 끊을 수도 있다.
shared_ptr
하나의 특정 객체를 참조하는 smart pointer가 총 몇 개인지를 참조하는 smart pointer이다.
여기서 reference counting이라는 개념이 등장하는데, 간단하게 말하면 해당 리소스를 몇 명이 가리키고 있는지를 세는 것이다.
shared_ptr
은 이러한 reference counting을 사용하여 소유권 공유를 지원한다.
shared_ptr
자체의 접근은 thread-free하다고 하는데, 몇 가지 문제점들이 있다.
이 부분은, 정내훈 님의 발표자료를 첨부한다.
https://www.slideshare.net/zzapuno/multithread-sharedptr
간단하게 말하면 shared_ptr
의 대상에 접근하는 것은 thread-safe하지만, shared_ptr
변수의 접근(load
, store
)은 thread-safe하지 않다라는 내용인데 자세한 것은 슬라이드를 참고하면 좋을 것 같다.
unique_ptr
처럼 shared_ptr
도 make_shared()
라는 함수로 생성한다.
unique_ptr
과 동일하게 get()
, reset()
메서드를 지원한다.
shared_ptr
은 본연의 목적에 맞게 reset()
을 호출해도 무조건 reset 되는 것이 아니라 마지막 shared_ptr일 때만 리소스가 해제된다.
weak_ptr
공부 더 해오겠습니다