2 분 소요

모던 C++

개요

컨테이너템플릿 인자를 보면 Allocator를 사용하는 버전이 있습니다.

1
2
3
4
template<typename T, typename Allocator = allocator<T>>
class vector {
    ...
};

할당자(Allocator)컨테이너의 메모리 할당을 직접 제어하여 성능을 향상시키는 도구입니다.(개체 생성과 소멸 참고)

구현 방법

할당자(Allocator)는 다음 주요 함수들을 구현해야 합니다.

항목 내용
allocate() n개 만큼 저장할 수 있는 메모리 영역을 할당합니다.
deallocate() allocate()에서 할당한 메모리를 해제합니다.
construct() 지정한 메모리 위치에 요소 개체의 생성자를 호출합니다.(위치 지정 생성 참고)
destroy() 지정한 메모리 위치에 요소 개체의 소멸자를 호출합니다.(위치 지정 생성 참고)
rebind (~C++17) 요소 타입에 대한 할당자(Allocator)를 이용하여 다른 타입용 컨테이너를 할당할 수 있게 합니다.

다음은 간단한 Allocator 구현 예입니다.

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
template<typename T>
class MyAllocator {
public:
    typedef size_t    size_type;
    typedef ptrdiff_t difference_type;
    typedef T*        pointer;
    typedef const T*  const_pointer;
    typedef T&        reference;
    typedef const T&  const_reference;
    typedef T         value_type;

    MyAllocator() {}
    MyAllocator(const MyAllocator&) {}

    // T를 n개 만큼 저장할 수 있는 메모리 영역을 할당합니다.
    pointer allocate(size_type n, const void * = 0) {
        T* t = (T*) malloc(n * sizeof(T));
        std::cout << "MyAllocator::allocate()" << std::endl;
        return t;
    }

    // allocate에서 할당한 메모리를 해제합니다.
    void deallocate(void* p, size_type) {
        free(p);
        std::cout << "MyAllocator::deallocate()" << std::endl;
    }

    pointer address(reference x) const {return &x;}
    const_pointer address(const_reference x) const {return &x;}
    MyAllocator<T>& operator =(const MyAllocator&) {return *this;}

    // p 메모리 위치에 val을 복사 생성합니다. 
    void construct(pointer p, const T& val) { 
        new (p) T(val);
    }
    // p 메모리 위치의 T 개체의 소멸자를 호출합니다.
    void destroy(pointer p) {
        p->~T();
    }

    // 지원되는 최대 할당 크기를 리턴합니다.
    size_type max_size() const {
        return std::numeric_limits<size_t>::max();
    }

    // T 타입에 대한 할당자(another)를 이용하여
    // 다른 타입인 U 타입용 컨테이너를 할당할 수 있게 합니다.
    // T::rebind<U>::other(another).allocate(10, static_cast<U*>(0));
    // C++17 부터 deprecate 되었습니다.
    // template<class U>
    // struct rebind {typedef MyAllocator<U> other;};

    // template<class U>
    // MyAllocator(const MyAllocator<U>&) {}

    // template<class U>
    // MyAllocator& operator =(const MyAllocator<U>&) {return *this;}
};

class A {
public:
    A() {
        std::cout << "A()" << std::endl;
    }
    A(const A& other) {
        std::cout << "A(const A& other)" << std::endl;        
    }
    ~A() {
        std::cout << "~A()" << std::endl;     
    }
};

std::vector<A, MyAllocator<A>> v;

v.push_back(A()); 

실행 결과는 다음과 같습니다.

1
2
3
4
5
6
A() // push_back() 의 인수인 A() 생성
MyAllocator::allocate() // 할당자로 컨테이너 메모리 영역 생성
A(const A& other) // 할당자의 construct()를 호출하여 할당한 메모리 영역에 A 복사 생성
~A() // push_back()시 임시로 생성한 개체 소멸
~A() // 할당자의 destroy()를 호출하여 할당한 메모리 영역의 개체 소멸
MyAllocator::deallocate() // 컨테이너 메모리 영역 해제

댓글남기기