치춘짱베리굿나이스

[Rank 5] ft_containers - Allocator 본문

42/42s Cursus

[Rank 5] ft_containers - Allocator

치춘 2023. 1. 19. 15:41

Allocator 클래스

컨테이너를 하기 위해 필수로 알아야 하는 클래스이다

앞의 반복자 파트에서는 전혀 쓸 일이 없었지만 벡터나 스택 같은 컨테이너들은 기본적으로 메모리 할당을 하고 그 안에 요소들을 저장해야 하며, 내부 메서드에서 메모리 일부 할당 및 해제가 잦기 때문에 Allocator의 사용법을 반드시 익혀야 한다

뭐 하는 녀석인지

C/C++에서는 메모리 관리를 위해서 malloc, calloc, free … 와 new, delete를 사용했었다

특정 변수를 위한 메모리를 할당하고자 한다면 이 함수들이 편리하지만, 직접 컨테이너를 구현할 때 (ft_containers 처럼) 는 이야기가 달라진다

컨테이너 내부에서는 특정 메서드를 호출할 때마다 일정 영역만 메모리를 해제하거나 재할당하는 등 다양하고 세밀한 동작을 요구하므로, new / delete 만으로는 한계가 있는 것이다

 

예를 들면, 벡터의 용량 (capacity) 을 늘리거나 줄일 때 (reserve), 벡터의 크기 (size) 를 늘릴 때 (resize) 는 인자로 받은 크기만큼 메모리를 재할당해 주어야 하는데, new 만으로는 이러한 조작이 애매해진다

new는 메모리 할당 뿐만 아니라 초기화도 동시에 진행하므로, 메서드를 통해 new를 자주 호출하게 되면 성능의 저하도 발생할 것이다

 

컨테이너를 만들기 위해선 allocator 를 쓰자

Allocator 클래스 구문

template <class T>
class allocator
  • 템플릿 클래스로, 어떤 자료형 (클래스) 의 메모리 공간을 할당 / 해제할 것인지 나타내는 클래스 T를 갖는다
  • allocator<memory> 헤더를 include하여 사용할 수 있다

타입 정의

pointer

T의 포인터 타입이다

reference

T의 참조 타입이다

const_pointer

T의 상수 포인터 (constant pointer) 타입이다

const_reference

T의 상수 참조 (constant reference) 타입이다

size_type

unsigned int 형식으로, allocator가 할당할 수 있는 메모리 영역의 단위 길이를 나타낸다

value_type

allocator가 다루는 타입으로, T와 같다

멤버 함수

생성자

allocator(); // 생성자
allocator(const allocator<T>& instance); // 복사 생성자
template <class T_>
allocator(const allocator<T_>& instance); // 복사 생성자
  • 새로운 allocator 객체를 생성한다

address

pointer address(reference val) const;
const_pointer address(const_reference val) const;
  • 인자로 들어온 요소 val의 주소를 반환한다

allocate

pointer allocate(size_type count, const void* _Hint = 0);
  • count개의 T 타입 메모리 영역을 새롭게 할당한다 (메모리 크기: count * sizeof(T))
  • _Hint는 근처의 메모리 주소를 넣을 수 있으며, 특정 주소의 근처에 새로운 메모리를 할당하고 싶다면 힌트로서 메서드에 제공할 수 있다
    • _Hint의 기본값은 0 (널 포인터) 이므로, 굳이 2번째 인자를 제공하지 않아도 자동으로 초기화된다
    • _Hint가 제공되면, 최대한 해당 주소에 가까운 곳에 새로운 메모리를 할당한다
  • 반환값 (pointer 타입) 은 새롭게 할당한 메모리 영역의 첫 번째 요소 주소이다

construct

void construct(pointer p, const_reference val);
  • 메모리는 할당되었지만 초기화되지 않은 메모리 주소 pT 타입의 객체를 생성 (Construct) 한다
  • 주소 pnew 키워드를 이용하여 T 생성자를 호출한 것과 똑같이 동작한다
    • 생성자의 인자로 val이 들어간다 (복사 생성자 호출)
    • new((void *)p) T(val) 과 동작이 같다

deallocate

void deallocate(pointer p, size_type n);
  • 메모리 주소 p가 가리키는 영역을 해제한다
    • 주소 p부터 총 n개의 T 타입 메모리 영역을 해제한다 (메모리 크기: n * sizeof(T))
  • 다만 이 함수를 호출하는 것이 내부에 초기화된 객체의 소멸자를 호출하지 않음에 주의하자

destroy

void destroy(pointer p);
  • 메모리 주소 p가 가리키는 영역의 소멸자를 호출한다
  • deallocate와 반대로, 이 함수는 메모리 영역 해제를 도와주진 않는다

max_size

size_type max_size() const throw();
  • 현재 할당 가능한 T 타입의 메모리 개수
    • allocate 등에서 사용되는 count의 최대값으로, 이 이상의 메모리를 할당받을 수 없다
    • allocate(count, 0) 이 성공할 수 있는 count의 최대값이라고 이해하자

비 멤버 함수

operator==

template <class T1, class T2>
bool operator==(const allocator<T1>& lhs, const allocator<T2>& rhs) throw();
  • == 연산자에 대한 오버로드
  • allocator 인스턴스를 비교하…긴 하는데, 기본 allocator는 무상태성을 띄므로 결과적으로 모든 allocator는 같다
    • 따라서 항상 true를 반환한다

operator!=

template <class T1, class T2>
bool operator!=(const allocator<T1>& lhs, const allocator<T2>& rhs) throw();
  • != 연산자에 대한 오버로드
  • == 오버로드와 마찬가지로, allocator의 무상태성 때문에 모든 allocator이 같음을 보장한다
    • 따라서 항상 false를 반환한다

참고 자료

https://en.cppreference.com/w/cpp/memory/allocator

https://cplusplus.com/reference/memory/allocator/

https://learn.microsoft.com/en-gb/cpp/standard-library/allocator-class?view=msvc-170#address

Comments