템플릿 구현 시 value type의 리스트를 만들었을 때 소멸자 문제
글쓴이: dragonHu / 작성시간: 금, 2017/05/12 - 9:42오후
안녕하세요 c++을 공부하고 있는 학생입니다.
list를 구현할때 소멸자에 대하여 궁금한점이 있어 질문드립니다.
template <typename T> class ChainNode { private: T data; ChainNode<T> * nextNode; friend class Chain<T>; }; template <typename T> class Chain { private: ChainNode<T> * front; public: class ChainIterator { }; };
이러한 구조의 리스트를 만들려하는데요
Chain객체를 소멸하면 소멸자를 통해서 모든 노드들을 삭제하려합니다.
~ChainNode<T>() { delete data; delete nextNode; }
생각한 방법은 위와 같이 연쇄적으로 할 예정이였는데요(예외처리는 아직 염두에 두지 않았어요)
그런데
Chain<int>
이런식으로 포인터 타입이 아닌 value 타입으로 리스트를 선언하면 delete data; 를 할때 참조 수준이 달라서 컴파일 오류가 발생하잖아요
즉 T가 포인터 타입(data가 포인터 변수)이라면 ChainNode 의 멤버인 data 까지 해제하고
value 타입이라면 ChainNode만 해제하는 코드를 작성하고 싶은데
이 문제를 어떻게 해결해야 하는지 잘 모르겠습니다.
std list 헤더파일을 살펴는 봤는데 제가 읽기엔 너무 어려운 코드였습니다..
꼭 답변부탁드립니다 ㅠ
Forums:
멤버변수 int data에 대해서 delete
멤버변수
int data
에 대해서delete data;
가 가능할 거라고 생각하시는 이유가...?delete는 주소에 대해, 특히 new를 이용하여 동적 할당된 메모리 주소에 대해서 사용하는 것입니다.
일반 멤버 변수는 클래스 소멸 시 자동으로 같이 소멸하므로 소멸자에 따로 명시해 줄 필요는 전혀 없습니다.
죄송합니다 글 수정했어요
질문을 이상하게 했네요 죄송합니다.
다시 읽었습니다.
다시 읽었습니다.
그러니까,
T
가int
일 때는 별다른 처리를 하지 않지만,T
가int *
할 때는delete
하도록Class ChainNode
의 소멸자를 짜겠다는 거죠?짧게 말씀드리지요. 좋은 생각이 아닙니다.
애초에
int *
가delete
해도 안전하다는 보장을 누가 해 주는데요?오직
new
로 할당된 주소만이delete
로 해제할 수 있습니다.하지만 그렇지 않은 경우가 있죠. 그것도 엄청 다양하게!
1) 지역 변수, 전역 변수 혹은 정적 변수의 주소
당연히
delete
를 포함한 어떤 방법으로도 해제 안 됩니다.2)
malloc
,calloc
혹은realloc
으로 할당된 메모리 주소free
로 해제해야죠.3) 동적 할당된 구조체, 공용체, 클래스 등의 멤버 주소
당연히 원래 객체를 통째로 해제해 줘야 합니다.
4)
new int[]
으로 할당한 배열의 한 요소원래의 배열을
delete []
으로 해제해 줘야 합니다5) 기타.
alloca
로 할당받았던가, memory-mapped file이 매핑된 주소라던가 등 플랫폼에서 제공하는 온갖 종류의 메모리 공간 할당 방법들!제각각 자기만의 해제 방법이 따로 있답니다.
보통
int *
하나 툭 던져주면 이게 해제할 수 있는 건지, 어떻게 해제해야 하는 건지 알아낼 표준적인 방법은 전혀 없습니다. 좀 일반적으로 말해서,T *
라고 해도 마찬가집니다. 실제로std::list
도T *
따위를 던져서 instantiation 하면 원소가 삭제될 때 포인터가 가리키는 메모리를 삭제하려는 시도 따위 전혀 하지 않습니다. 애초에 할 수 있는 방법이 없으니까요. 그래서 STL container에 동적 할당된 포인터들을 채워 놓고 remove-erase 구문 따위를 돌리면 메모리가 줄줄 새지요.소멸자에서 포인터 필드에
delete
를 쓰려면, 그 포인터가 반드시new
로 할당되었음을 확신할 수 있어야 합니다. 대개private
포인터이고 자신이 직접new
로 할당되도록 작성했을 경우에는 그럴 수 있죠. 포인터가 외부에서 날라왔을 경우에는 그런 확신을 가지기 어렵습니다. 사용자 매뉴얼에 "꼭 new로 할당된 포인터만 전달해주세요"라고 써놓고 사용자의 지적 능력을 믿으시던가요.포인터가 소멸할 때 알아서 할당이 해제되도록 하고 싶으신가요? C++11에서 추가된 스마트 포인터들을 쓰세요.
http://en.cppreference.com/w/cpp/memory/unique_ptr
http://en.cppreference.com/w/cpp/memory/shared_ptr
어떻게든 포인터 타입과 비포인터 타입에 대해 다르게 동작하는 템플릿 코드를 작성하고 싶으신가요?
그런 분들을 위해서 제가 예제 코드를 준비해 오긴 했습니다.
C++11에서 추가된
is_pointer
를 쓰면 간단해지는데, 간혹 C++11을 사용할 수 없는 경우도 있을 수 있죠. 그래도 어떻게든 C++11 템플릿 라이브러리의 일부를 가져와서 구현할 수는 있었습니다. http://en.cppreference.com/ 에서 Possible implementation 좀 긁어왔습니다.중요하니까 다시 한 번.
T *
가 주어졌다고 항상delete
가 가능한 건 아닙니다. 위 코드는 포인터와 비포인터 타입 인수에 따라 다른 코드를 실행시키는 예시일 뿐, 절대 그대로 실용적인 목적으로 사용되어서는 안 됩니다.댓글 달기