C++ 이야기 아홉번째: Array를 가리킬 수 있는 Smart Pointer

Posted at 2007. 5. 14. 00:19 // in S/W개발/C++ 이야기 // by 김윤수


C++ 이야기 아홉번째입니다. 이번에는 저번글에서 말씀드린 대로 scoped_array, shared_array 에 대해 소개해 드리겠습니다.

scoped_array와 shared_array는 그 이름에서 쉽게 알 수 있듯이 scoped_ptrshared_ptr 의 array 버전입니다. 왜 굳이 scoped_ptr과 shared_ptr 하나로 그냥 객체 하나와 array 하나를 가리키지 않고, scoped_array 와 shared_array 라는 걸 따로 두었을까요 ?

그 이유는 C++ 이야기 세번째: new와 delete 라는 글을 보면 금방 아실 수 있습니다. 거기에 나왔던 내용을 다시 한 번 정리하자면,

* new: 객체 하나를 동적으로 할당하고, 초기화시켜 줍니다.
* delete: 객체 하나를 소멸시키고, 삭제합니다.
* new []: 객체의 배열을 동적으로 할당하고, 하나 하나를 초기화시켜 줍니다.
* delete []: 객체의 배열 하나 하나의 요소를 소멸시키고, 배열을 삭제합니다.
......
"new 로 할당했으면 delete 로 해제, new [] 로 할당했으면 delete []로 해제하시라"
라고 할 수 있습니다.

그러니, 그냥 객체 하나만 가리키는 경우와 객체의 배열을 가리키는 smart pointer 클래스를 따로 둘 수 밖에 없는 것이겠지요. 물론 이런 방법외에도 scoped_ptr이나 shared_ptr이 vector 표준 container를 가리키도록 한다면 거의 같은 효과를 낼 수 있겠지만, vector 와 같이 dynamic 하게 array의 크기가 늘었다 줄었다 할 필요가 없는 간단한 경우라면 vector의 overhead를 부담할 필요가 없을 것입니다. 그런 경우에는 당연히 scoped_array 와 shared_array가 훨씬 좋겠지요.

scoped_array는 scoped_ptr과 마찬가지로 noncopyable 에서 상속받으므로 복사할 수가 없고, scoped_array 객체가 소멸될 때 scoped_array가 가리키는 객체도 함께 소멸됩니다. 즉, scoped_ptr과 용도는 동일한데, array를 가리키는데 사용된다는 점만 다릅니다. array 를 가리키는데 사용되기 때문에 scoped_ptr 과는 한 가지 다른 점이 있습니다. 그건 아래에 보시는 대로 operator [] 가 override되어 있다는 것입니다.

namespace boost {

  template<class T> class scoped_array :
noncopyable {
  public:
    typedef T
element_type;

    explicit
scoped_array(T * p = 0); // never throws
   
~scoped_array(); // never throws
    void
reset(T * p = 0); // never throws
    T &
operator[](std::ptrdiff_t i) const; // never throws
    T *
get() const; // never throws
    operator
unspecified-bool-type() const; // never throws
    void
swap(scoped_array & b); // never throws
  };

  // never throws
  template<class T>
    void
swap(scoped_array<T> & a, scoped_array<T> & b);

}

array의 element를 가리킬 수 있게 하려면 당연한 것이겠지요.



그리고, shared_array는 shared_ptr의 array 버전이라고 생각하시면 되구요, 그 용도는 shared_ptr과 같습니다. 한 가지 다른 점은 이미 예상하셨겠지만 다음과 같이 operator []가 override되어 있다는 점입니다.

namespace boost {

  template<class T> class shared_array {
  public:
    typedef T
element_type;

    explicit
shared_array(T * p = 0);
    template<class D>
shared_array(T * p, D d);
   
~shared_array(); // never throws
   
shared_array(shared_array const & r); // never throws
    shared_array &
operator=(shared_array const & r); // never throws
    void
reset(T * p = 0);
    template<class D> void
reset(T * p, D d);
    T &
operator[](std::ptrdiff_t i) const() const; // never throws
    T *
get() const; // never throws
    bool
unique() const; // never throws
    long
use_count() const; // never throws
    operator
unspecified-bool-type() const; // never throws
    void
swap(shared_array<T> & b); // never throws
  };

  // all never throws
  template<class T>
    bool
operator==(shared_array<T> const & a,
                    shared_array<T> const & b);
  template<class T>
    bool
operator!=(shared_array<T> const & a,
                    shared_array<T> const & b);
  template<class T>
    bool
operator<(shared_array<T> const & a,
                   shared_array<T> const & b);
  template<class T>
    void
swap(shared_array<T> & a, shared_array<T> & b);

}


이쯤에서 scoped_array와 shared_array에 대한 소개는 마치구요. 이 정도 소개드리면 객체 array를 scoped_ptr 이나 shared_ptr로 가리키는 것이 마치 new [] 로 할당한 객체 array를 delete [] 가 아닌 delete 로 삭제하는 것과 비슷한 오류라는 것을 이해하실 거라고 생각하고, 저는 이만 물러 가겠습니다.

다음에는 최근 C++ library extension 으로 제안된 TR1에 대해서 소개해 드리도록 하겠습니다. 이전에 몇 가지 소개해드린 것들 중에 이미 TR1에 속해 있는 것들도 상당수 있습니다.

다음 글도 기대해 주시고, 앞으로 C++ 시리즈가 쭉~ 계속되기를 원하신다면 댓글 달아 주시는 센스 잊지 마세요~ 앞으로도 관심 있게 읽어 주시고, 소프트웨어 관련된 저의 다른 글들도 참고로 읽어 보세요.

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