본문 바로가기
C C++ - STL

STL - 13 allocator

by violetoz 2014. 2. 13.
[STL-13] allocator|STL을 배우자
2008.02.07 17:34

설날에 강좌업뎃 합니다.. ^^

 

이번에는 STL 모든 Container에서 기본으로 사용하는 allocator<T> 에 대한 기본적인 활용 예에 대하여

간단히 설명하고, allocator<T> 와 함께 사용하는 uninitialized_fill, uninitialized_fill_n, uninitialized_copy,

uninitialized_copy _n 사용 방법도 같이 보도록 하겠습니다.

 

메모리 관련된 부분이라 모든 것을 설명하기는 어려우니 궁금하신 점은 덧글 바랍니다.

 

보통 array의 상수 정의를 대신하기 위해 new로 memory 할당하는 형태의 class를 만드는 경우가 많지만,

좀 더 generic 한 형태로 자신의 Container에 memory control을 위해 allocator class를 사용하면 많은

이점이 있습니다.

 

allocator class를 사용하기 위해서는 <memory>를 include 하여야 합니다.

참고 http://msdn2.microsoft.com/en-us/library/96xh3xxe(VS.71).aspx

     http://www.sgi.com/tech/stl/table_of_contents.html (8. Memory allocation 을 참고하세요. )

 

아래의 예는 예전 강좌에서도 보여 드렸던 Standard library와 유사한 vector에서 push_back 기능을 제외한

Fixed vector입니다. 그리고 FixedVec을 이용한 실행 프로그램입니다.

 

FixedVec.hpp에서 주의 깊게 보아야 할 부분은 member function인 create()와 destroy() 입니다.

create는 세 가지로 overloading 되어 있습니다.

 

create()

    아무것도 하지않으며, data와 avail을 NULL로 지정합니다.

create( size_type, const T & )

    주어진 size 만큼 allocator의 member인 allocate를 이용하여 할당하고,

    uninitialized_fill을 이용하여 T type의 value로 initialize 합니다.

create( const_iterator, const_iterator)

    iterator을 이용하여 uninitialized_copy를 합니다.

    이때 주의 사항(당연한 것이지만)은 첫 번째 인자가 두 번째 인자 보다 앞이여야 합니다.

 

uninitialized_fill   = http://www.sgi.com/tech/stl/uninitialized_fill.html

                       http://msdn2.microsoft.com/en-us/library/a3txak8w(VS.71).aspx

uninitialized_fill_n = http://www.sgi.com/tech/stl/uninitialized_fill_n.html

                       http://msdn2.microsoft.com/en-us/library/k2302sd6(VS.71).aspx

uninitialized_copy   = http://www.sgi.com/tech/stl/uninitialized_copy.html

                       http://msdn2.microsoft.com/en-us/library/ctht4stc(VS.71).aspx

uninitialized_copy_n = http://www.sgi.com/tech/stl/uninitialized_copy_n.html

 

모두 iterator(pointer)를 인자로 요구하며, allocator로 할당된 공간에 대하여 처리를 합니다.

그리고, 링크 사이트의 예를 보시면 아시겠지만, malloc 으로 할당된 공간도 동일하게 처리합니다.

memcpy와 유사한 역할을 한다고 보시면 되겠죠.

 

destroy()

    할당된 부분의 모든 요소를 allocator의 member인 destroy로 제거(파괴) 하고 할당된 메모리

    공간을 deallocate로 제거(파괴) 합니다.

 

allocator class는 별도의 operator를( [], -> ) 를 제공하지 않으며 ( operator ==, != 은 사용할 수 있습니다 )

iterator로 정의된 pointer의 operator로 접근하고 처리 할 수 있습니다.

FixedVec.hpp에 operator[] 정의를 참고 하세요. 

 

FixedVec.hpp

 1 #include <algorithm>
 2 #include <cstddef>
 3 #include <memory>
 4 #include <stdexcept>
 5 
 6 template < typename T >
 7 class FixedVec{
 8 public:
 9     typedef         T*              iterator;
10     typedef const   T*              const_iterator;
11     typedef         T&              reference;
12     typedef const   T&              const_reference;
13     typedef         T               value_type;
14     typedef         size_t          size_type;
15 
16     FixedVec() { create(); }                                                ///< default construct
17     explicit FixedVec( size_type n, const T& t = T() ) { create( n, t ); }  ///< construct overloading
18     FixedVec( const FixedVec& fv ) { create( fv.begin(), fv.end() ); }      ///< copy construct
19     virtual ~FixedVec() { destroy(); }                                      ///< destruct
20 
21     //! operator overloading
22     FixedVec&           operator=   ( const FixedVec& );                    ///< assignment
23     value_type&         operator[]  ( size_type i ) { return data[i]; }     ///< operator []
24     const value_type&   operator[]  ( size_type i ) const { return data[i]; }///< const T operator[]
25 
26     //! public method
27     size_type           size        ()  const   { return avail - data;  }   ///< return value is to allocate size of FixedVec
28     iterator            begin       ()          { return data;          }   ///< data iterator
29     const_iterator      begin       ()  const   { return data;          }   ///< data const_iterator
30     iterator            end         ()          { return avail;         }   ///< avail iterator
31     const_iterator      end         ()  const   { return avail;         }   ///< avail const_iterator
32 
33     void                clear       ()          { destroy();            }   ///< same destroy
34     bool                empty       ()  const   { return data == avail; }   ///< empty
35 private:
36     iterator            data;                                               ///< first element in the FixedVec
37     iterator            avail;                                              ///< (one past) the last element in the FixedVec
38     std::allocator<T>   alloc;                                              ///< object to handle memory allocation
39 
40     void                create      ();                                     ///< memory allocation initialize
41     void                create      ( size_type, const T& );                ///< memory allocation by size and value
42     void                create      ( const_iterator, const_iterator );     ///< memory allocation by iterator
43     void                Swap        ( FixedVec& );                          ///< container data swapping
44     void                destroy     ();                                     ///< memory deallocation
45 };
46 
47 template < typename T >
48 FixedVec< T >& FixedVec< T >::operator= ( const FixedVec< T > &rhs )
49 {
50     FixedVec< T > temp(rhs);
51     Swap( temp );
52     return *this;
53 }
54 
55 template < typename T >
56 void FixedVec< T >::create()
57 {
58     data = avail = 0;
59 }
60 
61 template < typename T >
62 void FixedVec< T >::create(size_type n, const T& val)
63 {
64     data = alloc.allocate(n);
65     avail = data + n;
66     std::uninitialized_fill(data, avail, val);
67 }
68 
69 template < typename T >
70 void FixedVec< T >::create(const_iterator i, const_iterator j)
71 {
72     data = alloc.allocate(j - i);
73     avail = std::uninitialized_copy(i, j, data);
74 }
75 
76 template < typename T >
77 void FixedVec< T >::destroy()
78 {
79     if (data) {
80         iterator it = avail;
81         while (it != data)
82             alloc.destroy(--it);
83         alloc.deallocate(data, avail - data);
84     }
85 
86     data = avail = 0;
87 }
88 
89 template < typename T >
90 void FixedVec< T >::Swap ( FixedVec< T > &rhs )
91 {
92     std::swap( alloc, rhs.alloc );
93     std::swap( data , rhs.data  );
94     std::swap( avail, rhs.avail );
95 }

 

main.cpp

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <string>
 4 #include <iterator>
 5 #include <stdexcept>
 6 
 7 #include "FixedVec.hpp"
 8 
 9 templatetypename T >
10 void PrintContainerElement( const T& t, const std::string title = "Container" )
11 {
12     typedef typename T::value_type type;
13     std::cout << title << " : ";
14     std::copy( t.begin(), t.end(), std::ostream_iterator< type >( std::cout, " " ) );
15     std::cout << std::endl;
16 }
17 
18 int main()
19 {
20     try{
21         FixedVec< std::string > fvecStrA;
22         FixedVec< std::string > fvecStrB( 15"B" );
23         FixedVec< std::string > fvecStrC( 20"C" );
24 
25         if( fvecStrA.empty() ){
26             std::cout << "fvecStrA was empty" << std::endl;
27         }
28 
29         PrintContainerElement( fvecStrA, "Fixed Vector A" );
30         
31         FixedVec< std::string >::size_type sz = 10;
32         fvecStrA = FixedVec< std::string >( sz, "A" );
33         PrintContainerElement( fvecStrA, "Fixed Vector A" );
34 
35         fvecStrA = fvecStrB;
36         fvecStrB = fvecStrC;
37 
38         std::cout << "fvecStrC size = " << fvecStrC.size() << std::endl;
39         forsize_t i = 0 ; i < fvecStrC.size() ; i++ ){
40             fvecStrC[i] = "TT";
41         }
42 
43         PrintContainerElement( fvecStrA, "Fixed Vector A" );
44         PrintContainerElement( fvecStrB, "Fixed Vector B" );
45         PrintContainerElement( fvecStrC, "Fixed Vector C" );
46 
47         std::cout << std::endl;
48         std::cout << "fvecStrA size = " << fvecStrA.size() << std::endl;
49         std::cout << "fvecStrB size = " << fvecStrB.size() << std::endl;
50         std::cout << "fvecStrC size = " << fvecStrC.size() << std::endl;
51     }
52     catch ( const std::exception &error ){
53         std::cerr << error.what() << std::endl;
54         std::exit( EXIT_FAILURE );
55     }
56     catch (...) {
57         std::cerr << "Unknown error precess halted." << std::endl;
58         std::exit( EXIT_FAILURE );
59     }
60 
61     return EXIT_SUCCESS;
62 }

 

실행 결과는 아래와 같습니다.

---------- run ----------
fvecStrA was empty
Fixed Vector A : 
Fixed Vector A : A A A A A A A A A A 
fvecStrC size = 20
Fixed Vector A : B B B B B B B B B B B B B B B 
Fixed Vector B : C C C C C C C C C C C C C C C C C C C C 
Fixed Vector C : TT TT TT TT TT TT TT TT TT TT TT TT TT TT TT TT TT TT TT TT

fvecStrA size = 15
fvecStrB size = 20
fvecStrC size = 20

출력 완료 (0초 경과) - 정상 종료