Namespaces
Variants

C++ named requirements: Allocator

From cppreference.net
C++ named requirements

객체의 접근/주소 지정, 할당/해제 및 생성/소멸을 위한 전략을 캡슐화합니다.

스토리지 할당 또는 해제가 필요할 수 있는 모든 표준 라이브러리 구성 요소는 std::string , std::vector 및 모든 컨테이너 (단, std::array 제외) (C++11부터) std::inplace_vector (C++26부터) 부터 std::shared_ptr std::function (C++17 이전) 까지 다음 요구 사항을 충족하는 클래스 타입의 객체인 Allocator 를 통해 이를 수행합니다.

많은 할당자 요구 사항들의 구현은 선택적입니다. 왜냐하면 모든 AllocatorAwareContainer 가 할당자에 접근할 때 std::allocator_traits 를 통해 간접적으로 접근하며, std::allocator_traits 가 이러한 요구 사항들에 대한 기본 구현을 제공하기 때문입니다.

목차

요구사항

주어진

  • T , 비-const, 비-참조 타입 (C++11까지) 비-const 객체 타입 (C++11부터) (C++17까지) cv-한정되지 않은 객체 타입 (C++17부터) ,
  • A , Allocator 타입의 T 타입에 대한 할당자,
  • a , A 타입의 객체,
  • B , A 를 재바인딩하여 얻은 cv-한정되지 않은 객체 타입 U 에 대한 해당 Allocator 타입,
  • b , B 타입의 객체,
  • p , std:: allocator_traits < A > :: pointer 타입의 값으로 std:: allocator_traits < A > :: allocate ( ) 호출로 얻음,
  • cp , std:: allocator_traits < A > :: const_pointer 타입의 값으로 p 로부터 변환으로 얻음,
  • vp , std:: allocator_traits < A > :: void_pointer 타입의 값으로 p 로부터 변환으로 얻음,
  • cvp , std:: allocator_traits < A > :: const_void_pointer 타입의 값으로 cp 또는 vp 로부터 변환으로 얻음,
  • xp , cv-한정되지 않은 객체 타입 X 에 대한 역참조 가능한 포인터,
  • r , * p 표현식으로 얻은 T 타입의 lvalue,
  • n , std:: allocator_traits < A > :: size_type 타입의 값.
내부 타입
타입 식별자 별칭 타입 요구 사항
A::pointer (선택적) (지정되지 않음) [1]
A::const_pointer (선택적) (지정되지 않음)
A::void_pointer (선택적) (지정되지 않음)
  • 다음을 만족함 NullablePointer .
  • A::pointer A::void_pointer 로 변환 가능함.
  • B::void_pointer A::void_pointer 가 동일한 타입임.
A::const_void_pointer (선택적) (지정되지 않음)
  • 다음을 만족함 NullablePointer .
  • A::pointer , A::const_pointer , 및 A::void_pointer A::const_void_pointer 로 변환 가능함.
  • B::const_void_pointer A::const_void_pointer 가 동일한 타입임.
A::value_type T
A::size_type (선택적) (지정되지 않음)
  • 부호 없는 정수 타입.
  • A 가 할당할 수 있는 가장 큰 객체의 크기를 표현할 수 있음.
A::difference_type (선택적) (지정되지 않음)
  • 부호 있는 정수 타입.
  • A 에 의해 할당된 객체에 대한 임의의 두 포인터의 차이를 표현할 수 있음.
A::template rebind<U>::other
(선택적) [2]
B
  • 임의의 U 에 대해, B::template rebind<T>::other A 임.
포인터 연산
표현식 반환 타입 요구 사항
* p T&
* cp const T & * cp * p 가 동일한 객체를 가리킴.
p - > m (원본 유지) ( * p ) . m 와 동일함, 단 ( * p ) . m 가 유효하게 정의된 경우.
cp - > m (원본 유지) ( * cp ) . m 와 동일함, 단 ( * cp ) . m 가 유효하게 정의된 경우.
static_cast < A :: pointer > ( vp ) (원본 유지) static_cast < A :: pointer > ( vp ) == p
static_cast < A :: const_pointer > ( cvp ) (원본 유지) static_cast < A :: const_pointer > ( cvp ) == cp
std:: pointer_traits < A :: pointer > :: pointer_to ( r ) (원본 유지)
저장소 및 수명 연산
표현식 반환 타입 요구 사항
a. allocate ( n ) A::pointer T[n] 타입의 배열 객체에 적합한 저장소를 할당하고 배열을 생성하지만, 배열 요소는 생성하지 않습니다. 예외를 던질 수 있습니다. n == 0 인 경우 반환 값은 명시되지 않습니다.
a. allocate ( n, cvp ) (선택적) a. allocate ( n ) 와 동일하지만, 지역성을 지원하기 위해 cvp ( nullptr 또는 a. allocate ( ) 로부터 얻은 포인터)를 명시되지 않은 방식으로 사용할 수 있습니다.
a. allocate_at_least ( n ) (선택적) (C++23부터) std:: allocation_result

< A :: pointer >

T[cnt] 타입의 배열 객체에 적합한 저장소를 할당하고 배열을 생성하지만 배열 요소는 생성하지 않으며, { p, cnt } 를 반환합니다. 여기서 p 는 저장소를 가리키는 포인터이고 cnt n 이상입니다. 예외를 던질 수 있습니다.
a. deallocate ( p, n ) (사용되지 않음) p 가 가리키는 저장소를 해제합니다. p 는 이전 allocate 또는 allocate_at_least (C++23부터) 호출에서 반환된 값이어야 하며, 그 사이에 deallocate 호출로 무효화되지 않아야 합니다. n 은 이전에 allocate 에 전달된 값과 일치하거나 allocate_at_least 를 통해 요청된 요소 수와 반환된 요소 수 사이의 값이어야 합니다(어느 한계값과 같을 수 있음). (C++23부터) 예외를 던지지 않습니다.
a. max_size ( ) (선택적) A::size_type A :: allocate ( ) 에 전달할 수 있는 가장 큰 값입니다.
a. construct ( xp, args... ) (선택적) (사용되지 않음) 이전에 할당된 저장소의 xp 가 가리키는 주소에 X 타입의 객체를 생성하며, args... 를 생성자 인자로 사용합니다.
a. destroy ( xp ) (선택적) (사용되지 않음) xp 가 가리키는 X 타입의 객체를 파괴하지만, 저장소는 해제하지 않습니다.
인스턴스 간의 관계
표현식 반환 타입 요구사항
a1 == a2 bool
  • true 는 할당자 a1 가 할당한 저장 공간을 a2 를 통해 해제할 수 있을 때만.
  • 반사적, 대칭적, 추이적 관계를 설정함.
  • 예외를 발생시키지 않음.
a1 ! = a2
  • ! ( a1 == a2 ) 와 동일함.
선언 효과 요구사항
A a1 ( a ) a1 == a 가 되도록 a1 을 복사 생성함.
(참고: 모든 Allocator CopyConstructible 를 만족함.)
  • 예외를 발생시키지 않음.
A a1 = a
A a ( b ) B ( a ) == b 이고 A ( b ) == a 가 되도록 a 를 생성함.
(참고: 이는 rebind 로 관련된 모든 할당자들이 메모리 풀과 같은 서로의 자원을 유지함을 의미함.)
  • 예외를 발생시키지 않음.
A a1 ( std :: move ( a ) ) a1 a 의 이전 값과 같도록 생성함.
  • 예외를 발생시키지 않음.
  • a 의 값은 변경되지 않고 a1 == a 임.
A a1 = std :: move ( a )
A a ( std :: move ( b ) ) a A ( b ) 의 이전 값과 같도록 생성함.
  • 예외를 발생시키지 않음.
타입 식별자 별칭 타입 요구사항
A::is_always_equal
(선택적)
std::true_type 또는 std::false_type 또는 이들로부터 파생됨.
  • true 는 타입 A 의 임의의 두 할당자가 항상 동일하게 비교될 경우.
  • (제공되지 않으면, std::allocator_traits 는 이를 std:: is_empty < A > :: type 으로 기본 설정함.)
컨테이너 연산에 미치는 영향
표현식 반환 타입 설명
a. select_on_container_copy_construction ( )
(선택적)
A
  • 현재 a 를 사용하는 컨테이너로부터 복사 생성되는 컨테이너에서 사용할 A 의 인스턴스를 제공합니다.
  • (일반적으로 a 의 복사본이나 기본 생성된 A 를 반환합니다.)
타입 식별자 별칭 타입 설명
A::propagate_on_container_copy_assignment
(선택적)
std::true_type 또는 std::false_type 또는 이들로부터 파생된 타입.
  • A 타입의 할당자를 사용하는 컨테이너가 복사 할당될 때 할당자를 복사해야 하는 경우 std::true_type 또는 이로부터 파생된 타입입니다.
  • 이 멤버가 std::true_type 또는 이로부터 파생된 타입인 경우, A CopyAssignable 을 만족해야 하며 복사 연산은 예외를 던지지 않아야 합니다.
  • 소스와 대상 컨테이너의 할당자가 동일하지 않은 경우, 복사 할당은 이전 할당자를 사용하여 대상의 메모리를 해제한 후 새로운 할당자를 사용하여 메모리를 할당하고 요소(및 할당자)를 복사해야 합니다.
A::propagate_on_container_move_assignment
(선택적)
  • A 타입의 할당자를 사용하는 컨테이너가 이동 할당될 때 할당자를 이동해야 하는 경우 std::true_type 또는 이로부터 파생된 타입입니다.
  • 이 멤버가 std::true_type 또는 이로부터 파생된 타입인 경우, A MoveAssignable 을 만족해야 하며 이동 연산은 예외를 던지지 않아야 합니다.
  • 이 멤버가 제공되지 않거나 std::false_type 으로부터 파생되었고 소스와 대상 컨테이너의 할당자가 동일하지 않은 경우, 이동 할당은 소스 메모리의 소유권을 가져올 수 없으며 필요에 따라 자체 메모리 크기를 조정하면서 요소들을 개별적으로 이동 할당하거나 이동 생성해야 합니다.
A::propagate_on_container_swap
(선택적)
  • A 타입의 할당자를 사용하는 두 컨테이너를 교환할 때 할당자들을 교환해야 하는 경우 std::true_type 또는 이로부터 파생된 타입입니다.
  • 이 멤버가 std::true_type 또는 이로부터 파생된 타입인 경우, A 타입은 Swappable 을 만족해야 하며 교환 연산은 예외를 던지지 않아야 합니다.
  • 이 멤버가 제공되지 않거나 std::false_type 으로부터 파생되었고 두 컨테이너의 할당자가 동일하지 않은 경우, 컨테이너 교환의 동작은 정의되지 않습니다.

참고 사항:

  1. 아래의 fancy pointers 도 참조하십시오.
  2. rebind 는 이 할당자가 SomeAllocator<T, Args> 형태의 템플릿인 경우에만 선택사항입니다(이때 Args 는 0개 이상의 추가 템플릿 타입 매개변수이며, std::allocator_traits 에 의해 제공됨).

주어진

  • x1 x2 , (서로 다른 타입일 수 있는) X::void_pointer , X::const_void_pointer , X::pointer , 또는 X::const_pointer 타입의 객체들
그러면, x1 x2 동등한 값 을 가지는 포인터 값인 것은, 오직 x1 x2 모두가 이 네 가지 타입만을 사용하는 일련의 static_cast 를 통해 X::const_pointer 타입의 두 개의 해당 객체 px1 px2 로 명시적으로 변환될 수 있고, 표현식 px1 == px2 true 로 평가되는 경우에 한합니다.

주어진

  • w1 w2 , X::void_pointer 타입의 객체들
그런 다음, 표현식 w1 == w2 w1 ! = w2 에 대해 하나 또는 두 객체 모두가 동등한 값 을 갖는 X::const_void_pointer 타입의 객체로 대체될 수 있으며, 의미에는 변화가 없습니다.

주어진

  • p1 p2 , X::pointer 타입의 객체들
그런 다음, 표현식들 p1 == p2 , p1 ! = p2 , p1 < p2 , p1 <= p2 , p1 >= p2 , p1 > p2 , p1 - p2 에 대해, 하나 또는 두 객체 모두를 동등한 값 을 가지는 X::const_pointer 타입의 객체로 대체하더라도 의미에는 변화가 없습니다.

위 요구사항들은 Container iterator const_iterator 를 비교할 수 있게 합니다.

할당자 완전성 요구사항

타입 T 에 대한 할당자 타입 X 는 다음 두 조건 모두가 T 가 완전한 타입인지 여부와 관계없이 참일 경우 할당자 완전성 요구사항 을 추가적으로 만족합니다:

  • X 가 완전한 타입입니다.
  • value_type 을 제외한 std:: allocator_traits < X > 의 모든 멤버 타입들이 완전한 타입입니다.
(C++17부터)

상태 저장 및 상태 비저장 할당자

모든 Allocator 타입은 stateful 이거나 stateless 입니다. 일반적으로 stateful allocator 타입은 서로 다른 메모리 리소스를 나타내는 unequal 값을 가질 수 있는 반면, stateless allocator 타입은 단일 메모리 리소스를 나타냅니다.

사용자 정의 allocator가 stateless일 필요는 없지만, 표준 라이브러리에서 stateful allocator의 사용 여부와 방법은 구현에 따라 정의됩니다. 동일하지 않은 allocator 값을 사용하는 경우, 구현이 이러한 사용을 지원하지 않으면 구현에 따라 정의된 런타임 오류나 정의되지 않은 동작이 발생할 수 있습니다.

(until C++11)

사용자 정의 allocator는 상태를 포함할 수 있습니다. 각 컨테이너나 다른 allocator-aware 객체는 제공된 allocator의 인스턴스를 저장하며 std::allocator_traits 를 통해 allocator 교체를 제어합니다.

(since C++11)

상태 비저장 할당자 타입의 인스턴스는 항상 동일하게 비교됩니다. 상태 비저장 할당자 타입은 일반적으로 빈 클래스로 구현되며 empty base class optimization 에 적합합니다.

멤버 타입 is_always_equal std::allocator_traits 에서 할당자 타입이 상태를 가지지 않는지 여부를 결정하기 위해 의도적으로 사용됩니다.

(C++11부터)

팬시 포인터

멤버 타입 pointer 가 raw pointer 타입이 아닌 경우, 일반적으로 "fancy pointer" 라고 부릅니다. 이러한 포인터들은 세그먼트 메모리 아키텍처를 지원하기 위해 도입되었으며, 현재는 raw pointer로 접근하는 동종 가상 주소 공간과 다른 주소 공간에 할당된 객체들에 접근하기 위해 사용됩니다. fancy pointer의 예시로는 매핑 주소 독립 포인터 boost::interprocess::offset_ptr 가 있으며, 이를 통해 std::set 과 같은 노드 기반 데이터 구조를 공유 메모리와 각 프로세스에서 다른 주소로 매핑된 메모리 매핑 파일에 할당할 수 있습니다. Fancy pointer는 이를 제공한 allocator와 독립적으로 사용할 수 있습니다 , 클래스 템플릿 std::pointer_traits 를 통해 (C++11부터) . 함수 std::to_address 를 사용하여 fancy pointer에서 raw pointer를 얻을 수 있습니다. (C++20부터)

표준 라이브러리에서 화려한 포인터(fancy pointers) 및 사용자 정의 크기/다른 타입 사용은 조건부로 지원됩니다. 구현에서는 멤버 타입 pointer , const_pointer , size_type , 그리고 difference_type 이 각각 value_type* , const value_type * , std::size_t , 그리고 std::ptrdiff_t 이어야 할 수 있습니다.

(C++11 이전)

개념(Concept)

쿼리 객체 std::get_allocator 의 정의를 위해 다음의 설명 전용(표현 전용) 개념이 정의됩니다.

template < class Alloc >

concept /*simple-allocator*/ = requires ( Alloc alloc, std:: size_t n )
{
{ * alloc. allocate ( n ) } - > std:: same_as < typename Alloc :: value_type & > ;
{ alloc. deallocate ( alloc. allocate ( n ) , n ) } ;
} && std:: copy_constructible < Alloc >

&& std:: equality_comparable < Alloc > ;

설명 전용(표현 전용) 개념 /*simple-allocator*/ Allocator 요구 사항의 최소 사용성 제약 조건을 정의합니다.

(C++26부터)

표준 라이브러리

다음 표준 라이브러리 구성 요소들은 Allocator 요구 사항을 충족합니다:

기본 할당자
(클래스 템플릿)
다중 수준 컨테이너를 위한 다중 수준 할당자 구현
(클래스 템플릿)
생성 시 사용된 std::pmr::memory_resource 기반의 런타임 다형성을 지원하는 할당자
(클래스 템플릿)

예제

C++11 할당자를 보여주는 예제입니다. [[ nodiscard ]] 는 C++20 스타일에 맞추기 위해 추가되었습니다.

#include <cstdlib>
#include <iostream>
#include <limits>
#include <new>
#include <vector>
template<class T>
struct Mallocator
{
    typedef T value_type;
    Mallocator() = default;
    template<class U>
    constexpr Mallocator(const Mallocator <U>&) noexcept {}
    [[nodiscard]] T* allocate(std::size_t n)
    {
        if (n > std::numeric_limits<std::size_t>::max() / sizeof(T))
            throw std::bad_array_new_length();
        if (auto p = static_cast<T*>(std::malloc(n * sizeof(T))))
        {
            report(p, n);
            return p;
        }
        throw std::bad_alloc();
    }
    void deallocate(T* p, std::size_t n) noexcept
    {
        report(p, n, 0);
        std::free(p);
    }
private:
    void report(T* p, std::size_t n, bool alloc = true) const
    {
        std::cout << (alloc ? "Alloc: " : "Dealloc: ") << sizeof(T) * n
                  << " bytes at " << std::hex << std::showbase
                  << reinterpret_cast<void*>(p) << std::dec << '\n';
    }
};
template<class T, class U>
bool operator==(const Mallocator <T>&, const Mallocator <U>&) { return true; }
template<class T, class U>
bool operator!=(const Mallocator <T>&, const Mallocator <U>&) { return false; }
int main()
{
    std::vector<int, Mallocator<int>> v(8);
    v.push_back(42);
}

가능한 출력:

Alloc: 32 bytes at 0x2020c20
Alloc: 64 bytes at 0x2023c60
Dealloc: 32 bytes at 0x2020c20
Dealloc: 64 bytes at 0x2023c60

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
LWG 179 C++98 pointer const_pointer 가 서로
비교 가능하도록 요구되지 않음
요구됨
LWG 199 C++98 a.allocate(0) 의 반환 값이
명확하지 않음
명시되지 않음
LWG 258
( N2436 )
C++98 할당자 간 동등 관계가 반사적, 대칭적,
또는 추이적일 것을 요구하지 않음
반사적, 대칭적,
추이적일 것을 요구
LWG 274 C++98 T 가 const 한정 타입이나 참조 타입일 수 있어
std::allocator 가 올바르지 않을 수 있음 [1]
이러한 타입들 금지
LWG 2016 C++11 할당자의 복사, 이동, 스왑 연산이
사용 시 예외를 던질 수 있음
예외를 던지지 않아야 함
LWG 2081 C++98
C++11
할당자가 복사 할당(C++98)과 이동 할당(C++11)을
지원하도록 요구되지 않음
요구됨
LWG 2108 C++11 할당자가 상태를 가지지 않음을 나타낼 방법이 없음 is_always_equal 제공
LWG 2263 C++11 LWG 이슈 179 의 해결책이 C++11에서
실수로 누락되고 void_pointer const_void_pointer 로 일반화되지 않음
복원 및 일반화
LWG 2447 C++11 T 가 volatile 한정 객체 타입일 수 있음 이러한 타입들 금지
LWG 2593 C++11 할당자로부터 이동 시 값이 변경될 수 있음 변경 금지
P0593R6 C++98 allocate 가 할당한 저장 공간에
배열 객체를 생성하도록 요구되지 않음
요구됨
  1. std::allocator 의 멤버 타입 reference const_reference 는 각각 T& const T& 로 정의됩니다.
    • 만약 T 가 참조 타입인 경우, reference const_reference 는 잘못된 형식입니다 (참조에 대한 참조는 형성될 수 없기 때문이며, 참조 축소 는 C++11에서 도입되었습니다).
    • 만약 T 가 const 한정자를 가진 경우, reference const_reference 는 동일하며, address() 의 오버로드 집합은 잘못된 형식입니다.