polymorphic_allocator : 언제, 왜 사용해야합니까?


122

여기cppreference에 대한 문서가 있습니다 . 여기 에 작업 초안이 있습니다.

실제 목적이 무엇인지 polymorphic_allocator, 언제 / 왜 / 어떻게 사용 해야하는지 이해하지 못했음을 인정 해야합니다.
예를 들어 pmr::vector에는 다음과 같은 서명이 있습니다.

namespace pmr {
    template <class T>
    using vector = std::vector<T, polymorphic_allocator<T>>;
}

polymorphic_allocator제안은 무엇입니까 ? std::pmr::vector구식과 관련 하여 제안은 무엇입니까 std::vector? 지금까지 할 수 없었던 지금은 무엇을 할 수 있습니까?
할당 자의 실제 목적은 무엇이며 실제로 언제 사용해야합니까?


1
그들은 allocator<T>본질적으로 가지고있는 몇 가지 문제를 극복하려고합니다 . 따라서 할당자를 자주 사용하면 가치를 볼 수 있습니다.
edmz

2
관련 논문 .
edmz

답변:


103

cppreference의 선택 인용문 :

이 런타임 다형성을 통해 polymorphic_allocator를 사용하는 객체는 동일한 정적 할당 자 유형에도 불구하고 런타임에 다른 할당 자 유형을 사용한 것처럼 동작 할 수 있습니다.

"일반"할당 자의 문제는 컨테이너 유형을 변경한다는 것입니다. vector특정 할당 자와 함께 하려는 경우 Allocator템플릿 매개 변수를 사용할 수 있습니다 .

auto my_vector = std::vector<int,my_allocator>();

이제 문제는이 벡터가 할당자가 다른 벡터와 동일한 유형이 아니라는 것입니다. 예를 들어, 기본 할당 자 벡터가 필요한 함수에 전달하거나 다른 할당 자 유형을 가진 두 벡터를 동일한 변수 / 포인터에 할당 할 수 없습니다. 예 :

auto my_vector = std::vector<int,my_allocator>();
auto my_vector2 = std::vector<int,other_allocator>();
auto vec = my_vector; // ok
vec = my_vector2; // error

다형성 할당자는 템플릿 메커니즘을 통하지 않고 동적 디스패치를 ​​통해 할당 자 동작을 정의 할 수있는 멤버가있는 단일 할당 자 유형입니다. 이를 통해 특정 사용자 정의 할당을 사용하지만 여전히 공통 유형 인 컨테이너를 가질 수 있습니다.

할당 자 동작의 사용자 정의는 할당 자에게 다음을 제공하여 수행됩니다 std::memory_resource *.

// define allocation behaviour via a custom "memory_resource"
class my_memory_resource : public std::pmr::memory_resource { ... };
my_memory_resource mem_res;
auto my_vector = std::pmr::vector<int>(0, &mem_res);

// define a second memory resource
class other_memory_resource : public std::pmr::memory_resource { ... };
other_memory_resource mem_res_other;
auto my_other_vector = std::pmr::vector<int>(0, &mes_res_other);

auto vec = my_vector; // type is std::pmr::vector<int>
vec = my_other_vector; // this is ok -
      // my_vector and my_other_vector have same type

내가보기에 남아있는 주요 문제는 std::pmr::컨테이너가 여전히 std::기본 할당자를 사용하는 동등한 컨테이너 와 호환되지 않는다는 것 입니다. 컨테이너와 함께 작동하는 인터페이스를 디자인 할 때 몇 가지 결정을 내려야합니다.

  • 전달 된 컨테이너에 사용자 지정 할당이 필요할 수 있습니까?
  • 그렇다면 템플릿 매개 변수를 추가해야합니까 (임의 할당자를 허용하기 위해) 아니면 다형성 할당 자의 사용을 의무화해야합니까?

템플릿 솔루션은 다형성 할당자를 포함한 모든 할당자를 허용 하지만 다른 단점이 있습니다 (생성 된 코드 크기, 컴파일 시간, 코드는 헤더 파일에 노출되어야하며 문제를 계속 외부로 밀어내는 "유형 오염"가능성이 있음). 반면에 다형성 할당 자 솔루션은 다형성 할당자를 사용해야 함을 나타냅니다 . 이것은 std::기본 할당자를 사용하는 컨테이너를 사용하는 것을 배제 하고 레거시 코드와의 인터페이스에 영향을 미칠 수 있습니다.

일반 할당 자와 비교할 때 다형성 할당자는 memory_resource 포인터의 스토리지 오버 헤드 (무시할 가능성이 높음) 및 할당을위한 가상 함수 디스패치 비용과 같은 약간의 비용이 있습니다. 실제로 가장 큰 문제는 다형성 할당자를 사용하지 않는 레거시 코드와의 호환성이 부족하다는 것입니다.


2
그렇다면 std::pmr::클래스의 바이너리 레이아웃 이 다를 가능성이 매우 높습니까?
Euri Pinhollow 2017 년

12
@EuriPinhollow 당신은 당신이 요구하는 것이라면 reinterpret_casta std::vector<X>와 사이에 있을 수 없습니다 std::pmr::vector<X>.
davmac

4
메모리 리소스가 런타임 변수에 의존하지 않는 간단한 경우, 좋은 컴파일러는 가상화를 해제하고 추가 비용없이 다형성 할당 자로 끝납니다 (실제로 문제가되지 않는 포인터 저장 제외). 언급 할 가치가 있다고 생각했습니다.
DeiDei

1
@ Yakk-AdamNevraumont " std::pmr::컨테이너는 여전히 std::기본 할당자를 사용하는 동등한 컨테이너 와 호환되지 않습니다 " . 하나에서 다른 것으로 정의 된 할당 연산자도 없습니다. 확실 하지 않은 경우 시도해보십시오. godbolt.org/z/Q5BKev(gcc/clang 은 "실험적"네임 스페이스에 다형성 할당 클래스가 있기 때문에 코드가 위와 정확히 같지 않습니다).
davmac

1
@davmac 아, 그래서 template<class OtherA, std::enable_if< A can be constructed from OtherA > vector( vector<T, OtherA>&& )생성자 가 없습니다 . 확실하지 않았고 TS 호환 pmr이있는 컴파일러를 어디서 찾을 수 있는지 몰랐습니다.
Yakk-Adam Nevraumont

33

polymorphic_allocatorstd::function직접 함수 호출 과 마찬가지로 사용자 지정 할당 자에 대한 것 입니다.

선언 시점에서 어떤 할당자를 결정할 필요없이 컨테이너와 함께 할당자를 사용할 수 있습니다. 따라서 둘 이상의 할당자가 적절한 상황이있는 경우 polymorphic_allocator.

인터페이스를 단순화하는 데 사용되는 할당자를 숨기거나 다른 런타임 케이스로 교체 할 수 있기를 원할 수 있습니다.

먼저 할당자가 필요한 코드가 필요한 다음 pmr 벡터를 고려하기 전에 어느 것이 사용되는지 스왑 할 수 있어야합니다.


7

다형성 할당 자의 한 가지 단점 polymorphic_allocator<T>::pointer은 항상 T*. 즉, 멋진 포인터 와 함께 사용할 수 없습니다 . vector공유 메모리 에 a의 요소를 배치 하고 boost::interprocess::offset_ptrs를 통해 액세스 하려면이를 위해 일반 오래된 비다 형성 할당자를 사용해야합니다.

따라서 다형성 할당자는 컨테이너의 정적 유형을 변경하지 않고도 할당 동작 을 변경할 수 있지만 할당이 무엇인지 제한합니다 .


2
이것은 요점이며 큰 실망입니다. Arthur O'Dwyer의 Towards 의미있는 멋진 포인터 논문은 그의 저서 "Mastering the c ++ 17 STL"
sehe

다형성 할당자를 사용하는 실제 사용 사례를 제공 할 수 있습니까?
darune
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.