프로그래밍/Morden C++

<memory> std::allocator<T> 클래스

MAKGA 2021. 10. 31. 21:53
320x100

기본적으로 STL에 제공되는 할당자 클래스다.

하지만 이는 사용자가 임의로 커스텀해서 사용할 수 있다.

커스텀을 위해선 특정 인터페이스를 만족해야 한다.

 

주의 사항으로는

1. 템플릿으로 만들어야 하며, 템플릿 매개 변수에는 실제로 사용할 객체의 타입 T를 사용한다.

2. 비정적 데이터 멤버를 가질 수 없다.

3. allocate / deallocate 함수를 가져야 하며, allocate의 인자로 객체 T가 필요한 갯수를 넘겨야 한다.

4. 반환하는 포인터는 void*가 아닌 실제 타입의 포인터(T*) 이여야 한다.

 

cAlloc() = default;
~cAlloc() = default;

allocator도 결국엔 template class 이기 때문에, 생성자와 소멸자를 작성해야하는데, allocator 가 하는 일은 T 타입의 포인터를 할당 해제 해주는 Factory 라고 생각하면 쉽다.

생성자 내에선 해줄 일이 없고, 다른 함수에서 작성한다.

 

struct rebind {
	using other = cAlloc<U>;
};

 

rebind는 어떤 종류의 객체를 얻기 위해 사용된다.

std::list와 Obj라는 타입이 있을 때, std::list<T, Obj> 할당자는 T를 할당하기 위한 A 이지만, 실제로 내부에서 list는 노드 기반으로 구성되어야 한다. 이렇게 T 타입이 아닌 다른 타입으로도의 할당(node)이 필요해지는데, 이와 같은 요구 사항을 충족하기 위해 rebind를 가져야 17한다. (C++17에서 사용 중지 권고, C++20에서 삭제 예정)

rebind pattern : https://rookiecj.tistory.com/118

관련 stackoverflow : https://stackoverflow.com/questions/54092334/how-to-avoid-rebind-in-allocatort-n-c17

 

template<class _Value_type,
	class _Voidptr>
	struct _List_node
		{	// list node
		using _Nodeptr = _Rebind_pointer_t<_Voidptr, _List_node>;
		_Nodeptr _Next;	// successor node, or first element if head
		_Nodeptr _Prev;	// predecessor node, or last element if head
		_Value_type _Myval;	// the stored value, unused if head
 //중략

결과적으로 list<T>는 rebind<_List_node>::other를 참조함으로써, T 객체의 할당자를 통해 위의 List_node를 찾게 된다.

( 자세한 설명은 https://rookiecj.tistory.com/118 이곳을 보자 )

( 사실 C++17 부턴, rebind가 사용중지 권고가 내려져 정의하지않아도 컴파일은 잘 된다. )

 

template <typename U>
cAlloc(const cAlloc<U>& other) { }

다른 타입 (U) 에 대한 복사 생성자를 정의해준다.

 

 

pointer allocate(size_type ObjectNum, const_void_pointer hint) {
    allocate(ObjectNum);
}
pointer allocate(size_type ObjectNum) {
    return static_cast<pointer>(operator new(sizeof(T) * ObjectNum));
}

초기화 되지 않은 곳의 n * sizeof(T) 바이트 만큼을 할당합니다.

지역참조를 위해 hint 라는 포인터를 사용할 수 있습니다. ( 구현자가 지원하는 경우 가깝에 만드려고 시도할 수 있음 )

( const_void_pointer 를 받는 allocate는 C++17부터 사용중지 권고가 내려졌다. )

 

 

void deallocate(pointer p, size_type ObjectNum) {
    operator delete(p);
}

pointer에 의해 참조되는 곳을 할당 해제한다. deallocate가 삭제하는 곳은 꼭 allocate가 할당한 저장소여야 한다.

 

 

size_type max_size() const { return std::numeric_limits<size_type>::max() / sizeof(value_type);

이 container가 사용할 수 있는 최대 용량

 

 

template<typename U, typename... Args>
void construct(U *p, Args&& ...args) {
	new(p) U(std::forward<Args>(args)...);
}

template <typename U>
void destroy(U *p) {
	p->~U();
}

실제로 allocate 된 곳에 새로운 형태의 오브젝트를 생성하는 construct와 destroy 함수

construct 와 allocate는 container 의 reserve와 resize 를 생각하면 이해하기 쉬움

reserve : 생성자를 호출하지 않고 사이즈 만큼 공간을 예약 ( allocate )만 해둠

resize : 사이즈만큼 공간을 할당 ( allocate ) 하고, 사이즈만큼 생성자 ( construct ) 를 호출함

 

#pragma once
#include <limits>
template <typename T>
class cAlloc {
public:
	using value_type = T;

	using pointer = T * ;
	using const_pointer = const T*;

	using void_pointer = void*;
	using const_void_pointer = const void*;

	using size_type = size_t;

	using difference_type = std::ptrdiff_t;

	cAlloc() = default;
	~cAlloc() = default;
	template <typename U>
	struct rebind {
		using other = cAlloc<U>;
	};
	template <typename U>
	cAlloc(const cAlloc<U>& other) { }
	pointer allocate(size_type ObjectNum, const_void_pointer hint) {
		allocate(ObjectNum);
	}
	pointer allocate(size_type ObjectNum) {
		return static_cast<pointer>(operator new(sizeof(T) * ObjectNum));
	}
	void deallocate(pointer p, size_type ObjectNum) {
		operator delete(p);
	}
	size_type max_size() const { return std::numeric_limits<size_type>::max() / sizeof(value_type); }

	template<typename U, typename... Args>
	void construct(U *p, Args&& ...args) {
		new(p) U(std::forward<Args>(args)...);
	}

	template <typename U>
	void destroy(U *p) {
		p->~U();
	}
};

 

 

 

https://docs.microsoft.com/ko-kr/cpp/standard-library/allocator-base-class?view=msvc-160&viewFallbackFrom=vs-2019

https://help.perforce.com/sourcepro/11.1/html/toolsug/11-6.html

https://openmynotepad.tistory.com/58?category=854742 

https://www.youtube.com/watch?v=pP15kDeXJU0 

https://www.youtube.com/watch?v=kSWfushlvB8

https://jacking75.github.io/Cpp_EASTL/

https://woo-dev.tistory.com/51

 

320x100

'프로그래밍 > Morden C++' 카테고리의 다른 글

smart pointer 삭제자 지정  (0) 2022.01.27
시간 관련  (0) 2022.01.17
std::min, std::max 사용시  (0) 2021.10.06
std::map  (0) 2021.10.05
std::clamp  (0) 2021.09.29