스마트 포인터 활용
shared_ptr의 활용법과 발생할 수 있는 문제와 해결방안을 살펴보겠습니다.
linked list, tree 같은 자료구조에서 smart pointer의 아름다움을 한껏 느낄 수 있습니다. 제가 자주 사용하는 방법인 트리구조에서의 활용을 살펴보겠습니다. shared_ptr을 배우기 전까지는 자식노드 정보를 저장하기 위해 일반적인 포인터를 사용하였을 것입니다.
Tree와 같은 자료구조를 사용 시, 일반적으로 각 노드들은 힙메모리에 할당되므로 보통 포인터 대신 shared_ptr을 적용할 수 있습니다.
보통 포인터가 아닌 shared_ptr을 이용했을 때의 장점은 단연 메모리 해제에 있습니다. 기존의 Node 클래스는 하위 노드부터 제거해나가야 하므로, Tree라는 래퍼클래스를 더 만들어 주어 후위 순회를 하며 메모리를 해제시켜주어야 합니다.
하지만 shared_ptr을 이용한 Node 클래스는 래퍼클래스가 필요하지도, 소멸자에서 딱히 해줄 일도 없이 차근차근 메모리가 해제되는 기분 좋은 현상을 볼 수 있습니다. 노드가 해제되면 shared_ptr도 해제되고, 뒤이어 그것이 가리키고 있던 메모리도 해제되기 때문입니다. 자기를 가리키는 유일한 shared_ptr이 없어짐으로써 자신도 해제되는 그림입니다. 스마트 포인터의 장점을 한껏 보여줄 수 있는 예제로 충분합니다.
주의사항이 있습니다.
앞의 포스트(스마트 포인터)에서 살펴보았듯이 스마트포인터에는 스택메모리 주소를 보관해서는 안 됩니다. 만약 스택에 할당된 메모리를 트리에 보관한다면, 사용자의 의도와는 다르게 해제될 수 있고, 하위 노드들에 대한 정보를 모두 잃어버릴 수 있습니다.
그렇기에 만약 스택메모리에 할당된 정보를 트리구조로서 관리하고자 한다면 똑같은 복사본을 만들어 사용하는 수 밖에 없습니다. 그리고 이것은 불필요한 정보의 중복현상이 발생합니다.
예전에 작성한 코드라 앞의 것과 이어지는 것은 아니지만, 요점은 새로운 Tree(Node로 보아도 됩니다.)를 오른쪽 자식으로서 삽입하고자 할 경우, 스택주소는 스마트포인터가 관리해서는 안 되기 때문에 make_shared 메서드를 통해 right의 복제본을 생성, 저장한다는 것입니다. 결국에는 똑같은 정보를 가진 객체를 컴퓨터는 2개를 소유하게 됩니다. 스택에 하나, 힙에 하나.
이 같은 문제는 메모리 관리에서도 번거롭습니다. ‘앞으로 쓰지도 않을 스택 메모리 해제해 불필요한 정보 중복을 막아주어야겠다!’ 라고 생각한다면
이런 방법을 쓸 수는 있겠습니다. 스택메모리에 담긴 정보를 없애고 싶은 것이므로 할 수 있는 최대한 스택메모리는 스코프 안에서 해결하는 것입니다. 그러나 이것은 한 눈에 보아도 번거롭고 이런 메모리를 관리하기 위해 신경 쓴다는 것이 스마트 포인터의 사용 목적과는 맞지 않다고 생각합니다.
스마트 포인터에서의 문제는 항상 스택 메모리의 정보를 관리하고자 할 경우 생겨납니다. 일정 스코프 안에서만 사용할 변수가 아닌 경우에는 힙메모리에 할당하여 관리하는 습관을 들이는 것이 좋을 것 같습니다. 특히나 객체의 크기가 큰 경우에는 많은 복제시간과 스택,힙 중복 저장은 결코 효율적이지 않습니다. 변수를 힙에 할당해야할지, 힙에 할당해야할지에 대해서 좀 더 신중한 판단과 공부가 필요할 것 같습니다. 이번 활용편은 여기서 마치겠습니다.
Comments
Post a Comment