2012-03-13 1 views
4

할당 자 유형 (표준 섹션 17.6.3.5에 정의 된대로)을 템플릿 인수로 취하는 클래스 템플릿을 디자인하고 싶습니다. A의 누락 된 회원을 std::allocator_traits<A>이 유용하게 채우는 것을 봅니다. 그 외에도, 표준 라이브러리 나 할당자를 올바르게 사용하는 데 도움이되는 사항이 있습니까? 특히std :: allocator_traits의 사용 <A>

:

  1. std::allocator_traits<A>::propagate_on_container_copy_assignment 같은 형식 정의를 존중하기 위해, 나는 형 A의 멤버가 각 클래스의 특정 멤버 함수에 이런 일을 확인해야합니까? 아니면이 물건을 처리 할 멤버 대신 사용할 수있는 래퍼 유형이 있습니까?

  2. 사용자가 볼 수있는 개체 옆에 여분의 데이터를 저장하여 할당 횟수를 줄이기 위해 전체 할당을하려면 할당자를 이와 같이 리 바인드하는 것이 적절합니까?

.

template<typename T, typename A> 
class MyClass 
{ 
private: 
    //... 
    struct storage { 
     int m_special_data; 
     T m_obj; 
    }; 
    typedef typename std::allocator_traits<A>::template rebind_alloc<storage> 
     storage_alloc; 
    typedef typename std::allocator_traits<A>::template rebind_traits<storage> 
     storage_traits; 
    storage_alloc m_alloc; 

    static T* alloc(T&& obj) 
    { 
     storage_traits::pointer sp = storage_traits::allocate(m_alloc, 1); 
     sp->m_special_data = 69105; 
     return ::new(&sp->m_obj) T(std::move(obj)); 
    } 
    //... 
}; 

답변

10

나는 정말allocator_traits가 간단 모든 상용구 코드를 제공하여, 할당자를 작성할 수있다, 인생을 더 쉽게 만드는 아무것도 모르겠지만, 사용 할당자를 도움이되지 않습니다. 나는 모두 C++ 03 내가 GCC 4.7에 <ext/alloc_traits.h>을 추가 C++ (11) 코드에서 하나의 할당 API를 사용할 수 있도록

는 클래스 템플릿 __gnu_cxx::__alloc_traits는 C++ 11 모드에서 allocator_traits를 사용하는 일관된 API를 제공합니다 C++ 03 모드에서 할당 자에서 직접 관련 멤버 함수를 호출합니다.

  1. 아니, 래퍼 또는 바로 가기 없다는 C++ 11 할당 요구 사항은 컨테이너 저자의 작업이 훨씬 더 복잡합니다. 요구 사항은 메모리를 관리하는 방법에 따라 컨테이너마다 약간 씩 다릅니다. 벡터와 비슷한 유형의 경우 복사 할당 연산자에서 propagate_on_container_copy_assignment (POCCA)이 거짓이고 기존 용량이 원본 객체 크기보다 큰 경우 기존 메모리를 다시 사용할 수 있습니다 (POCCA가 true이고 새 할당자가 할당자를 대체 한 후에 나중에 할당을 해제 할 수 없기 때문에 오래된 메모리를 다시 사용할 수는 없다.)하지만 최적화는 목록이나 맵과 같은 노드 기반 컨테이너에별로 도움이되지 않는다. .

    당신은 아마 어떤 사용 [container.requirements.general]/3 용기에 명시된 바와 같이

    A a(m_alloc);  
    std::allocator_traits<A>::construct(a, &sp->m_obj, std::move(obj)); 
    return &sp->m_obj; 
    

return ::new(&sp->m_obj) T(std::move(obj)); 

을 대체 할 있지만, 거의 바로 보이는

  • 할당 자 allocator_traits<A>::construct을 사용하여 요소 유형 T을 만들지 만 할당 된 다른 유형 (예 : storage)은을 사용하면 안됩니다.

    자체가 부재 allocator_traits<A>::construct 나중에 명시 적으로 초기화 될 수 std::aligned_storage<sizeof(T)> 같이 초기화 남아있을 수있는 타입이 아니라면 그럼 storage::m_obj를 구성 할 구성된다 storage 경우

    . 대안 적으로, 사소한 구성을 필요로하는 각 부재를 개별적으로 구성한다. storagestring 멤버가 있다면 : 수명이 빨리 저장 그것을 위해 할당으로 시작되도록

    storage_traits::pointer sp = storage_traits::allocate(m_alloc, 1); 
        sp->m_special_data = 69105; 
        ::new (&sp->m_str) std::string("foobar"); 
        A a(m_alloc);  
        std::allocator_traits<A>::construct(a, &sp->m_obj, std::move(obj)); 
        return &sp->m_obj; 
    

    m_special_data 멤버는 사소한 유형입니다. m_strm_obj 회원은 평범하지 않은 초기화가 필요하므로 생성자가 완료 될 때 수명이 시작됩니다. 이는 각각 new 및 construct 호출에 의해 수행됩니다.

    는 는

    편집 :

    A a(m_alloc);  
        std::allocator_traits<A>::construct(a, &sp->m_obj, std::move(obj)); 
    
    : 나는 최근 표준 (I보고 한) 결함 및 construct에 대한 호출 반등 할당을 사용하지 않기 때문에이 라인을 가지고 배웠어요

    은 다음으로 대체 할 수 있습니다.

    std::allocator_traits<storage_alloc>::construct(m_alloc, &sp->m_obj, std::move(obj)); 
    

    이 때문에 수명이 약간 더 쉬워집니다.

  • +1

    "storage_traits :: construct (m_alloc, &sp);', 또는 'rebind'로 인해 계산되지 않습니까?) '저장소를 구성하면 어떻게됩니까? ''T'' 타입의 멤버를 가지고 있다면 멤버는'storage'가 아니라'storage'와 함께 생성됩니다. 그래서''union'' 또는'static_cast''를' – aschepler

    +0

    @aschepler, +1, well spotted! 지금 고쳐 주신 고마워요 –

    +0

    두 번째 질문에 네, 합집합을 사용하거나 알맞은 크기로 배열 된'char' 배열을 사용할 수 있습니다. 'storage'가'T'와는 별개로 구성 가능한 데이터만을 포함하고 있는지 확인하는 것이 더 쉽기 때문에'T'를'생성 '하고 단순히 다른 부분 (대개 포인터 및/또는 정수)에 값을 할당 할 수 있습니다. 내 대답을 편집 할게. 그것을 반영하기 위해. –