#13. [레거시 C++ STL] 할당자(Allocator)
모던 C++
- (C++17~) polymorphic_allocator가 추가되어 할당시 런타임 다형성을 지원합니다. 메모리 리소스를 사용하여 메모리 풀을 손쉽게 만들 수 있습니다.
개요
컨테이너의 템플릿 인자를 보면 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() // 컨테이너 메모리 영역 해제
댓글남기기