김윤수의 이상계를 꿈꾸며  
대문으로
김윤수의 생활투자 | 도라홈스쿨 | 태그 | 지역태그 | 미디어로그 | 방명록 | 관리자 | 새글 쓰기   
 
C++ 이야기 첫번째: auto_ptr 템플릿 클래스 소개
제 블로그는 Windows Vista의 시스템 서체인 맑은 고딕을 사용하고 있습니다. Windows Vista 이전 버전의 OS에서 맑은 고딕을 사용하시려면 여기에서 Office 2007 Compatibility Pack을 다운로드 받으신 후, 이 글을 보시고 설정을 따라 하시면 미려한 맑은 고딕 서체로 제 블로그 글을 읽으실 수 있습니다

C++ 관련 글을 연재로 써볼까 합니다. 개발자가 아니신 분들이나 C++ 로 주로 개발하지 않으시는 분들은 별로 관심이 가는 내용이 아닐 것 같네요.

첫 글로 C++ Smart Pointer 중의 하나인 auto_ptr 템플릿 클래스에 대해 소개하겠습니다.

본격적으로 소개하기 전에 다음 코드를 한 번 보시죠.

class BigClass {
private:
  int m_nprop;

public:
  int GetProperty();
};

void f()
{
  BigClass* pbc = new BigClass();   // argument는 그냥 없다고 가정합니다.
  ......                                            // 이런 저런 일을 한다고 치구요.
  delete pbc;
}

위 코드의 위험성이 느껴지시나요 ? 느껴지신다면 대단한 프로그래밍 내공을 가지신 것입니다. 느껴지지 않는다 해도 너무 실망하지 마시구요. 제가 알려드릴테니.

중간에 이런 저런 일을 하는 동안 에러가 발생했는데, 리턴하기 전에 delete pbc를 빼먹거나 예외(exception)가 발생해서 delete pbc를 실행하지 못한 채로 중간에 함수 수행이 중단된다면 어떻게 될까요 ? 당연히 메모리가 샐 것입니다. 이런 문제를 해결하기 위해 가장 쉽게 생각할 수 있는 방법은 아무래도 다음과 같은 것이겠죠.

void f()
{
  BigClass* pbc = new BigClass();
  try {                                             // 이런 저런 일을 하는 부분을 try catch로 묶습니다
    ......
  }
  catch () {
    delete pbc;                                 // 객체를 없애고,
    throw();                                     // 예외를 전달
  }
  delete pbc;                                  // 정상적인 흐름에서 객체를 삭제
}

왠지 좀 구리지 않나요 ? 우선 제 눈에 제일 먼저 들어오는 것은 delete pbc가 두 번 반복된다는 거네요. f() 에서 동적 할당하는 객체가 pbc 하나밖에 없으니까 그렇지 두 개, 세 개씩으로 늘어나 거나 예외 종류별로 다른 로직으로 처리해야 한다면... 끔찍하겠죠. f()에서 실제로 하는 일은 아주 작은 코드이고, 대부분은 예외 처리 코드인, 배보다 배꼽이 큰 상황이 벌어질 것 입니다. 사실 이런 식의 코드는 에러를 유발할 가능성이 크기 때문에 유지 보수하는 데도 별로 좋지 않습니다. 코드를 이해하기도 쉽지 않구요.

auto_ptr은 이런 문제를 해결하기 위해 설계된 템플릿 클래스입니다. auto_ptr은 자신이 가리키고 있는 객체에 대한 "유일한" 소유자로서 작동합니다.(일단 소유자라는 말에 집중하시기 바랍니다. "유일한"의 의미는 나중에 말씀드리겠습니다) 바꿔 말하면, auto_ptr은 자신이 파괴될 때, 자신이 가리키고 있던 객체도 파괴합니다. 게다가 auto_ptr은 일반 포인터를 쓰는 것과 거의 동일하게 사용할 수 있습니다. 즉, '*' 연산자로 역참조를 할 수 있구요, '->' 연산자로는 멤버 변수나 멤버 함수를 접근할 수 있습니다. 다음과 같은 코드가 가능하다는 겁니다.

std::auto_ptr<BigClass> bcap(new BigClass());
BigClass bc = *bcap;
int nprop = bcap->GetProperty();

그렇다면 위에서 구리게 짠 코드는 어떻게 바꿀 수 있을까요 ? 벌써 눈치 채셨다구요. 예~ 훌륭하십니다.

// auto_ptr을 사용하려면 include 해야 합니다.
#include <memory>

void f()
{
  // RAII(Resource Acquisition Is Intialization) idiom대로 auto_ptr 초기화
  std::auto_ptr<BigClass> bcap(new BigClass());
  ......
} // 함수를 떠나기 전에 auto_ptr 지역 변수에 대한
  // 소멸자가 호출되면서 new BigClass()로 할당한 객체가 해제됩니다.





어때요? 깔끔하죠? 코드까지 깔끔해진데다가 예외 안전성까지 확보했으니 auto_ptr을 안 쓰고는 못 배기실 겁니다. 음... 근데 저기 실눈을 뜨고 보고 계시는 분이 있군요. 아~ 지금 쓰고 있는 컴파일러가 워낙 꼬져서 템플릿을 지원하지 않는다구요. "그럼 컴파일러를 바꾸세요"라고 말하면 아마 돌이 날아 오겠죠 ? 뭐 어쩔 수 없죠. 우리네 인생이 그런 것 아니겠습니까? 컴파일러가 고생하는 대신 여러분 손이 고생해야죠. 다음과 같이 auto_ptr과 비슷한 클래스를 직접 작성하시면 됩니다.

class BigClassAutoPtr {
private:
  BigClass* m_pbc;

public:
  explicit BigClassAutoPtr(BigClass* pbc = 0): m_pbc(pbc) {}
  ~BigClassAutoPtr() { delete m_pbc; }
  BigClassAutoPtr& operator*() { return *m_pbc; }
  BigClassAutoPtr* operator->() { return m_pbc; }
}

물론 위 정의는 아직 문제가 많습니다. 바로 컴파일러가 자동으로 생성하는 복사 생성자와 복사 대입 연산자(copy assignment operator) 때문에 발생하는 문제입니다. 컴파일러가 자동으로 생성하는 복사 생성자와 복사 대입 연산자는 public 인터페이스에 속하고, member-wise copy로 동작하게 되어 있거든요. 구체적으로 어떻게 문제가 발생하는지 어떻게 auto_ptr에서는 해결하고 있는지는 다음 기회에 말씀 드리겠습니다.

마지막으로 템플릿을 지원하는 환경에서 템플릿을 지원하지 않는 환경으로의 이식을 생각해서 코드를 작성하는 법에 대해 잠깐 언급하고 이번 이야기를 마칠까 합니다. 그 비법은 바로 typedef 마술을 사용하는 것입니다.

// BigClass.h에 다음과 같이 정의하세요
#ifdef TEMPLATE_SUPPORTED
#include <memory>
#endif

class BigClass { ...... };

#ifdef TEMPLATE_SUPPORTED
typedef std::auto_ptr<BigClass> BigClassAutoPtr;
#else
class BigClassAutoPtr { ...... };
#endif

// BigClass를 사용하는 쪽에서는 다음과 같이 작성하세요.
#include "BigClass.h"

void f()
{
  BigClassAutoPtr bcap(new BigClass());
  ......
}

다 알고 계셨다구요 ? 예~ 당연히 그러셔야죠.

다 읽어 보신 후에 잘못된 부분이나 추가할 부분이 있으면 알려주세요. 질문도 좋구요.

참고 문헌
C++ Standard Library: A Tutorial and Reference 4.2 auto_ptr class,Nicolai Josuttis 저
Effective C++ 3rd Edition, Chapter 3 Resource Management, Scott Meyers 저

(근데 새벽 3시에 깨서 뭐하고 있는 건지 모르겠네요... 갑자기 깼는데 잠이 안 와서리...)

소프트웨어 관련된 저의 다른 글들도 참고로 읽어 보세요.

소프트웨어는 soft 해야 제 맛이다
Flexible한 S/W 작성하기
소스코드 복사의 위험성
C++ 이야기 첫번째: auto_ptr 템플릿 클래스 소개
C++ 이야기 두번째: auto_ptr의 두 얼굴
C++ 이야기 세번째: new와 delete
C++ 이야기 네번째: boost::shared_ptr 소개
C++ 이야기 다섯번째: 내 객체 복사하지마!
C++ 이야기 여섯번째: 기본기 다지기(bool타입에 관하여)


크리에이티브 커먼즈 라이선스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
지금 인터넷을 돌아다니시는데, Internet Explorer 쓰시나요 ? 느리고 답답한데다 항상 보안의 위협을 느끼시 않으신가요 ? 만약 그렇다면 빠르고 안전한, 그리고

구글의 검색 광고인 AdWords 를 사용하시면 특정 검색어에 대해 여러분의 싸이트가 노출되도록 할 수 있습니다. 검색어를 통한 트래픽 유치에 관심이 있으시다면,

Tag : , , ,


BLOG main image
이상계는 이쪽에 속해있지 않고 저쪽에 속해 있다. 이쪽에 사는 우리는 이쪽에 머무르지 않고 저쪽을 꿈꾸며 살아야 한다. 여기 오는 모든이들이 저쪽의 충만함을 이쪽에서의 매일의 삶에 경험할 수 있기를... E-mail: (yesarang) at (yahoo.co.kr)
올블로그 어워드 탑100블로그
 블로그 구독



meet me at meet me at me2DAY
E-mail 주소를 입력하세요:


 블로그 검색
Google
 Notice
me2day 개설했습니다.
블로그 스킨 바꾸었습니다
제 블로그의 성격
 분류
분류 전체보기 (232)
IT동향 (22)
사회동향 (4)
기술정리 (10)
개인 (16)
기타 (23)
기독교신앙 (1)
S/W개발 (61)
블로깅 (13)
리뷰 (8)
구글이야기 (9)
인터넷오늘은 (61)
독서 (3)
 태그 목록
c++ SW 개발 북마크 프로그래밍 구글 블로그 인터넷오늘은 SW 프로그래밍팁 Programming Language S/W 개발 네이버 sw개발 고수 고수팁 고절가주팁 IT 검색 블로깅 전략 리뷰 c Technology 다음 블로거 RSS 독서 라이브러리 로깅
 달력
«   2008/07   »
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    
 최근글
김윤수의 인터넷 오늘은 - 200..
김윤수의 인터넷 오늘은 - 200..
김윤수의 인터넷 오늘은 - 200..
Visual Studio 2008 에서 CppU.. (1)
김윤수의 인터넷 오늘은 - 200..
 최근 댓글
감사합니다. 따라하니 잘 됩니..
이희국 - 06/26
Makefile Project Creator(MPC..
jspark - 06/18
저흰 FinalBuilder를 씁니다...
오스카 - 06/18
많이 편해졌죠 ? ^^
김윤수 - 06/17
헉.. BOOST 라이브러리가 설치..
풀리비 - 06/17
 최근 트랙백
김윤수의 생각
yesarang's me2DAY
김윤수의 생각
yesarang's me2DAY
new와 delete 연산자.
채윤이네집
김윤수의 생각
yesarang's me2DAY
TR1
Minthe Blog
 Archive
2008/07
2008/06
2008/05
2008/04
2008/03
2008/02
2008/01
2007/12
2007/11
2007/09
2007/08
2007/07
 링크 모음
[강추] Alones world
[강추] Veracious Information
[강추] 경제는 놀이다(경제 만..
[강추] 디지털 비즈니스 이야..
[강추] 따뜻한 이야기
[강추] 주네의 열린 소프트웨어
[개인] Chester's Blog
[개인] Future IT Products &..
[개인] Homo Scriptus
[개인] Rubadub Blog
 방문자 통계
Total : 315835
Today : 26
Yesterday : 106