2014-03-18 2 views
8

내 C++ 11 프로그램에서 활발하게 작성 및 삭제 된 일부 객체에 shared_ptr<T>을 사용합니다. 표준 할당자인 operator new은 병목 현상이 발생하므로 직접 작성하여 한 번에 많은 메모리를 할당 한 다음 요청시 make_shared에 전달하십시오. Unfortunatelly, 이것은 내가 할당 쓰기 처음이며, GCC는 다음 코드를 컴파일 할 수없는 이유는 아무 생각이 : 여기allocate_shared/make_shared와 함께 사용자 정의 할당자를 사용할 수 없습니다.

#include <memory> 

class MyAlloc { 
public: 
    typedef char* pointer; 
    typedef const char* const_pointer; 
    typedef char value_type; 

    char* allocate(size_t len) { 
    return new char[len]; 
    } 

    void deallocate(char *ptr) { 
    delete[] ptr; 
    } 
} my_alloc; 

int main() { 
    std::allocator_traits<MyAlloc>(); 
    // MyAlloc is a correct allocator, since allocator_traits can be instantiated 
    // If I comment the following line of code, compilation is successful 
    std::allocate_shared<int>(my_alloc, 0); 
    return 0; 
} 

내가 아주 간단한 스텁 할당 및 allocate_shared 하나의 호출을합니다. GCC 오류는 다음과 같습니다.

In file included from c:\soft\mingw\lib\gcc\mingw32\4.8.1\include\c++\ext\alloc_traits.h:36:0, 
       from c:\soft\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\stl_construct.h:61, 
       from c:\soft\mingw\lib\gcc\mingw32\4.8.1\include\c++\memory:64, 
       from a.cpp:1: 
c:\soft\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\alloc_traits.h: In substitution of 'template<class _Alloc> template<class _Tp> using rebind_traits = std::allocator_traits<typename std::__alloctr_rebind<_Alloc, _Tp>::__type> [with _Tp = std::_Sp_counted_ptr_inplace<int, MyAlloc, (__gnu_cxx::_Lock_policy)2u>; _Alloc = MyAlloc]': 
c:\soft\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\shared_ptr_base.h:517:33: required from 'std::__shared_count<_Lp>::__shared_count(std::_Sp_make_shared_tag, _Tp*, const _Alloc&, _Args&& ...) [with _Tp = int; _Alloc = MyAlloc; _Args = {int}; __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]' 
c:\soft\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\shared_ptr_base.h:986:35: required from 'std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_make_shared_tag, const _Alloc&, _Args&& ...) [with _Alloc = MyAlloc; _Args = {int}; _Tp = int; __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]' 
c:\soft\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\shared_ptr.h:316:64: required from 'std::shared_ptr<_Tp>::shared_ptr(std::_Sp_make_shared_tag, const _Alloc&, _Args&& ...) [with _Alloc = MyAlloc; _Args = {int}; _Tp = int]' 
c:\soft\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\shared_ptr.h:598:39: required from 'std::shared_ptr<_Tp1> std::allocate_shared(const _Alloc&, _Args&& ...) [with _Tp = int; _Alloc = MyAlloc; _Args = {int}]' 
a.cpp:19:40: required from here 
c:\soft\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\alloc_traits.h:204:66: error: invalid use of incomplete type 'struct std::__alloctr_rebind<MyAlloc, std::_Sp_counted_ptr_inplace<int, MyAlloc, (__gnu_cxx::_Lock_policy)2u>, false>' 
     using rebind_traits = allocator_traits<rebind_alloc<_Tp>>; 
                   ^
c:\soft\mingw\lib\gcc\mingw32\4.8.1\include\c++\bits\alloc_traits.h:65:12: error: declaration of 'struct std::__alloctr_rebind<MyAlloc, std::_Sp_counted_ptr_inplace<int, MyAlloc, (__gnu_cxx::_Lock_policy)2u>, false>' 
    struct __alloctr_rebind; 
      ^

왜 이런 일이 발생합니까? 할당자를 올바르게 작성하여 allocate_shared과 작동하도록하려면 어떻게해야합니까? 할당 자 (allocator)가 지원해야하는 다른 연산자와 유형 특성이 있음을 알고 있지만 GCC가 나에게 원하는 것에 대한 힌트는 볼 수 없습니다. 또한

그것은 voidshared_ptr<T>::some_weird_stuff 또는이보다 더 낫다처럼라도 (shared_ptr와 함께) 특정 할당을 위해 value_typechar 등을 사용 OK인가?

+1

'rebind' 회원 템플릿 (및 다른 것들)을 제공해야합니다. [allocator.requirements] 또는 [cppreference : Allocator requirements] (http://en.cppreference.com/w/cpp/concept/Allocator) – dyp

답변

12

은 .. 당신은이 템플릿이 필요, 당신은 리 바인드 및 종류와 필요 멤버의 할당과 할당 해제 운영자를 갖는 것도 좋습니다.

최소한
#include <memory> 

template<typename T> 
struct Allocator 
{ 
    typedef std::size_t size_type; 
    typedef std::ptrdiff_t difference_type; 
    typedef T* pointer; 
    typedef const T* const_pointer; 
    typedef T& reference; 
    typedef const T& const_reference; 
    typedef T value_type; 

    template<typename U> 
    struct rebind {typedef Allocator<U> other;}; 

    Allocator() throw() {}; 
    Allocator(const Allocator& other) throw() {}; 

    template<typename U> 
    Allocator(const Allocator<U>& other) throw() {}; 

    template<typename U> 
    Allocator& operator = (const Allocator<U>& other) { return *this; } 
    Allocator<T>& operator = (const Allocator& other) { return *this; } 
    ~Allocator() {} 

    pointer allocate(size_type n, const void* hint = 0) 
    { 
     return static_cast<T*>(::operator new(n * sizeof(T))); 
    } 

    void deallocate(T* ptr, size_type n) 
    { 
     ::operator delete(ptr); 
    } 
}; 

template <typename T, typename U> 
inline bool operator == (const Allocator<T>&, const Allocator<U>&) 
{ 
    return true; 
} 

template <typename T, typename U> 
inline bool operator != (const Allocator<T>& a, const Allocator<U>& b) 
{ 
    return !(a == b); 
} 


int main() 
{ 
    std::allocate_shared<int, Allocator<int>>(Allocator<int>(), 0); 
} 

, 할당 자 모양을 수있다 : 이것은 또한, 그러나 ... allocate_shared 작동 내가 사람의 유형 인 것이다

template<typename T> 
struct Allocator 
{ 
    typedef T value_type; 

    Allocator() noexcept {}; 

    template<typename U> 
    Allocator(const Allocator<U>& other) throw() {}; 

    T* allocate(std::size_t n, const void* hint = 0) 
    { 
     return static_cast<T*>(::operator new(n * sizeof(T))); 
    } 

    void deallocate(T* ptr, size_type n) 
    { 
     ::operator delete(ptr); 
    } 
}; 

template <typename T, typename U> 
inline bool operator == (const Allocator<T>&, const Allocator<U>&) 
{ 
    return true; 
} 

template <typename T, typename U> 
inline bool operator != (const Allocator<T>& a, const Allocator<U>& b) 
{ 
    return !(a == b); 
} 

, 나는 모든 기능을 선호 .. 상기 용기/기능에 의해 요구되거나 사용되지 않는 것조차도.

+1

대부분의 멤버는 생략 가능하고 allocator_traits는 적절한 기본값을 제공합니다. "가장 최하위"버전에 불필요한 타입이 있어도, '리바 인드'가 필요하지 않습니다. 'size_type'과'pointer'는 당신이 직접 사용하기 때문에 필요합니다. 그리고 암시 적으로 정의 된 복사 생성자는 괜찮습니다. –

+0

고맙습니다. 나는 그것을 게시 한 후에 깨달았다. 기본적으로 pre-C++ 11 용 할당자를 복사하여 약간 수정했습니다. 나는 최근 편집에서 최소한의 할당자를 제공했다. 나는 당신의 대답이 나의 것보다 더 낫고 더 적합하다고 생각합니다. – Brandon

+0

@CantChooseUsernames 아니, 그렇지 않았습니다. 하지만 점점 가까워지고있어. 'size_type','pointer','rebind'는'std :: allocator_traits'가 제공하는 기본값과 같으며'operator =='와'operator! ='가 필요합니다. (즉, Jonathan의 대답을보십시오) – Casey

11

사용자 지정 할당자가 C++ 할당 자 요구 사항을 충족하지 않습니다.

특히, 다른 유형의 개체를 할당하기 위해 리바운드를 지원하지 않습니다. 일반적으로 할당자는 메모리를 할당하는 유형으로 매개 변수화 된 템플릿입니다. allocate_shared은 할당자를 리 바인드하여 적절한 크기와 유형의 메모리 블록을 할당 할 수 있어야하므로 char 객체의 배열을 할당하지 않으려 고합니다.

// MyAlloc is a correct allocator, since allocator_traits can be instantiated 

이 올바른 가정 아닙니다. 인스턴스화 allocator_traits<MyAlloc>은 모든 구성원을 인스턴스화하지 않습니다.

또한, 확인이 특정 할당하여 할당 char의 할당을하게

에 대한 VALUE_TYPE로 문자를 사용하는 것입니다,하지만 some_internal_type_defined_by_the_library의 할당을 allocate_shared 필요하고 그래서에 std::allocator_traits<MyAlloc>::rebind_alloc<some_internal_type_defined_by_the_library>를 사용하려고 해당 유형에 대한 할당자를 가져 오지만 할당자는 리 바인드 요구 사항을 지원하지 않습니다.

당신의 할당은 다음 allocator_traitsMyAlloc<U>에 바인딩하는 방법을 결정할 수있는 형태 MyAlloc<T>의 템플릿을 주어, 그렇지 않은 경우는 유형 MyAlloc::rebind<U>::other이 유효합니다.

는 은 C++ 표준이 (가) C++ 할당 자 유형에 대한 최소 요구 사항 지원하는 할당의 예로서 다음을 보여줍니다

: 이것처럼


template <class Tp> 
struct SimpleAllocator { 
    typedef Tp value_type; 
    SimpleAllocator(ctor args); 
    template <class T> SimpleAllocator(const SimpleAllocator<T>& other); 
    Tp* allocate(std::size_t n); 
    void deallocate(Tp* p, std::size_t n); 
}; 
template <class T, class U> 
bool operator==(const SimpleAllocator<T>&, const SimpleAllocator<U>&); 
template <class T, class U> 
bool operator!=(const SimpleAllocator<T>&, const SimpleAllocator<U>&); 
+0

자세한 설명을 읽어 주셔서 감사합니다! – yeputons

관련 문제