Destructor가 왜 2번 불리는 거죠? :: 2007/12/12 11:56



오늘 같이 일하는 분들 중 가운데 한분으로부터 "왜 제 프로그램을 실행시키면 destructor가 2번 불리는 거죠?"라는 질문을 들었습니다.

소멸자는 명시적으로 불러주지 않는 한 (뭐 가령 obj.TheClass::~TheClass()와 같이 해 주지 않는 한) 절대로 두 번 불리지 않습니다. 따라서 '소멸자가 두 번 호출된다'는 증상은, 실제로는 '어디선가 객체가 두 개 생성되고 있기' 때문에 발생합니다.

따라서 그분과 저는 어디서 객체가 두 번 생성되는지를 찾아보기 시작했습니다. 그 분이"객체를 두 번 생성한 적이 없는데요?"라고 고개를 갸웃거리기 시작하셨기 때문에, 저는 문제는 딱 한가지 뿐일 거라고 생각했습니다. 여기서 '두번 생성'되는 오류를 겪고 있는 객체의 클래스를 B라고 하고, 그 클래스를 사용하는 다른 클래스를 A라고 해 보겠습니다. 저는 그 분께 "혹시 다음과 같이 작성된 코드가 있나요"라고 물었습니다.

class A {
    B b_obj;

public :

   ...

   const B get_b_obj() const {
      return b_obj;
   }
};

여기까지 이야기가 되고 나니까, 그분 혼자서도 버그를 찾아낼 수 있었습니다. 이 분이 작성한 코드의 문제는,  함수의 반환값을 선언하는 부분에 실수로 &를 빼먹는 바람에 get_b_obj()가 호출되는 순간 b_obj의 복사본 객체가 만들어졌다는 점이었습니다. 객체가 두개가 되었으니, 소멸자가 두 번 불리는 것처럼 보였을 밖에요.

const B& get_b_obj() const {
    return b_obj;
}

그럼 이런 문제를 방지하려면 어떻게 해야 하나요? 다음과 같은 대비책들을 생각해 볼 만 합니다.

  1. B의 복사 생성자를 private으로 선언한다.
  2. A의 get_b_obj() 메소드의 반환값을 const B* 로 만든다

만일 질문하신 분이 B의 복사 생성자를 private로 만들어 두었더라면 위의 오류를 컴파일 시간에 잡을 수 있었을 겁니다. 복사 생성자가 private이니, 반환값의 type으로 const B&를 해야 할 것을 const B와 같이 했으면 오류 메시지가 떴겠죠. 그러니 '여러 개의 객체를 만들 일이 없는' 클래스에 대해서는 복사 생성자를 private로 해두는 것도 좋겠어요.

또다른 해결책으로는 객체 레퍼런스 대신 포인터를 반환하는 것을 생각해 볼 수 있습니다. 포인터를 반환하도록 하면 저런 오류는 상당부분 줄일 수 있습니다. const B*에서 '*'를 빼먹는 실수를 저지르면 똑같은 문제가 발생하지 않느냐고 생각하실 수도 있는데, 그러려면 return &b_obj; 에서 &를 빼먹는 실수도 저질러야 하기 때문에 사실상 확률은 굉장히 낮아지죠. (*와 &를 빼먹는 실수를 한꺼번에 저질러야 저런 문제가 발생하거든요). 물론 포인터를 별로 좋아하지 않는 분들께는 이런 방법이 별로 마음에 들지 않으시겠지만 말이에요.











 

트랙백 주소 :: http://www.buggymind.com/trackback/85
성함
비밀번호
홈페이지 비밀글로
< PREV |  1  |  ...  89  |  90  |  91  |  92  |  93  |  94  |  95  |  96  |  97  |  ...  151  |  NEXT >