const list<MyClass>& find_myclass_list( ... ) {
// 구현은 여기에
}
그런데 find_myclass_list 함수를 구현하다보면, 내가 찾아서 반환해야 할 list<MyClass>가 없는 경우가 있어요. 그런 경우라면 기존에 없던 객체에 대한 reference를 반환해야 한다는 부담에 직면하게 됩니다. 그래서 보통 이런 경우를 이런 식으로 해결하려고들 합니다. 우선 가장 단순한 첫번째 방법은, find_myclass_list의 반환값 타입을 reference에서 pointer로 바꾸는 겁니다.
const list<MyClass>* find_myclass_list( ... ) {
// 구현은 여기에
}
이렇게 하면 반환할 리스트가 존재하는 경우에는 그 리스트에 대한 포인터를 반환하면 되고, 없으면 0 값을 반환해주면 됩니다. 그러면 받는 쪽에서 그에 대한 처리를 해주면 되겠죠. 하지만 이 방법은 몇가지 단점을 가집니다. 첫 번째는 이미 인터페이스가 확정되어서 코딩이 진행중일때에는 저런 변경 작업을 하기가 어려울 수 있다는 것이고, 두 번째는 이런 식으로 코딩을 할 경우, 저 인터페이스를 이용하는 쪽에서 반환값이 0(NULL)인지 아닌지를 명시적으로 검사하는 코드를 작성해야만 한다는 것이 바로 그것입니다.
따라서 가급적이면 인터페이스를 변경하지 아니하고 아주 적은 양의 코딩을 통해서 문제를 해결할 수 있다면 좋을 겁니다. 가장 좋은 방법은 empty list를 반환하는 것이죠. 왜 그럴까요? empty list를 반환하면 받는 쪽에서는 리스트에 대한 iteration logic만 작성하면 되거든요. 리스트 안에 아무것도 없다면 어차피 iteration해봐도 안에 아무것도 없으니, 아무 동작도 하지 않게 되겠죠. 그럼 아래와 같이 하면 될까요?
const list<MyClass>& find_myclass_list( ... ) {
...
return list<MyClass>();
}
아마 C/C++의 메모리 관련 문제에 익숙하신 분들이라면 잘 아시겠지만, local automatic 변수에 대한 reference를 반환하는 것은 자살행위입니다. 저 메모리는 함수가 리턴되는 순간 사라질 운명의 변수에 할당되어 있는 메모리고, 함수 반환결과로 받은 주소값을 통해 저 메모리를 엑세스하는 순간 프로그램은 뻗어버리게 될 테니까요. 이미 사라진 변수에 대한 참조는 segmentation fault나 general protection fault같은 험악한 오류를 유발하게 될 겁니다.
그럼 아래와 같이 하면 됩니까?
const list<MyClass>& find_myclass_list( ... ) {
...
list<MyClass>* r = new list<MyClass>();
return *r;
}
얼핏보면 우아한 해결책인것 같아 보이기도 합니다만, 그러면 저 메모리는 대체 누가 반환합니까? 저런 함수를 빈번하게 사용할 경우, 결국 memory leak이 발생하게 되겠죠.
그래서 제가 고안해 낸 해결책은 template을 사용해서 아래와 같은 클래스를 설계하는 것이었습니다.
template <typename T> class EMPTY_LIST {
static std::list<T>& Tlist() {
static std::list<T> list_;
return list_;
}public :
EMPTY_LIST() {}
operator const std::list<T>& () {
return Tlist();
}
};
이렇게 하시면 앞서의 함수 find_myclass_list를 아래와 같이 구현하시면 됩니다.
const list<MyClass>& find_myclass_list( ... ) {
...
return EMPTY_LIST<MyClass>();
}
위의 구현에서 static function Tlist를 사용한 이유는, template을 사용할 경우 static 변수 정의와 이용에 약간의 제약이 존재하기 때문이며, 이를 가장 간단한 방법으로 피해가기 위해서입니다. 조금만 살펴보시면 위의 template이 어떠한 원리로 동작하게 되는지 짐작하실 수 있으리라고 생각되므로 자세한 설명은 피하겠습니다.
'Languages > C++' 카테고리의 다른 글
| cgdb : 텍스트 기반의 gdb 인터페이스 (0) | 2007/12/18 |
|---|---|
| VI와 ctags (0) | 2007/12/18 |
| empty container의 반환 (0) | 2007/12/14 |
| 메모리 할당과 초기화는 다르다 (2) | 2007/12/14 |
| Destructor가 왜 2번 불리는 거죠? (0) | 2007/12/12 |
| pure virtual method called (2) | 2007/12/06 |
댓글을 달아 주세요