2017-03-09 17 views
2

최근에 std::allocator에 관심을 보였습니다. C++ 코드에 대한 설계 결정과 관련된 문제를 해결할 수있을 것이라고 생각했습니다.std :: allocator에 덤벼기

일부 문서를 읽었으며 Andrei Alexandrescu's one at CppCon 2015과 같은 일부 비디오를 보았습니다. 이제는 할당자가 작동한다고 생각하는 방식으로 작동하도록 설계되지 않았으므로 기본적으로 사용하지 말아야한다는 것을 이해했습니다.

이것이 실현되기 전에 나는 std::allocator의 사용자 정의 하위 클래스가 어떻게 작동 하는지를 알 수있는 테스트 코드를 작성했습니다.

그래서 질문이 할당 자는 C++에서 사용하는 방법에 대해 없음),하지만 내 테스트 코드 (제공 이유는 정확히 배울 그냥 궁금 해요 : 예상대로 분명히

은 ... 작동하지 않았다 아래)가 작동하지 않습니다.
사용자 지정 할당자를 사용하려고하기 때문에 아닙니다. TestAllocator에 대한

typedef std::basic_string< char, std::char_traits<char>, TestAllocator<char> > TestString; 

int main(void) 
{ 
    TestString s1("hello"); 
    TestString s2(s1); 

    s1 += ", world"; 

    std::vector< int, TestAllocator<int> > v; 

    v.push_back(42); 

    return 0; 
} 

전체 코드는이 질문의 끝에서 제공되는 ... 정확한 이유를보고 그냥 궁금해서.

여기에 std::basic_stringstd::vector과 함께 사용자 지정 할당자를 사용하고 있습니다.

std::basic_string을 사용하면 할당 자의 인스턴스가 실제로 생성 된 것을 볼 수 있지만 아무런 메서드도 호출되지 않습니다 ...
그러면 사용되지 않는 것 같습니다.

그러나 std::vector으로, 내 자신의 allocate 메서드가 실제로 호출되고 있습니다.

여기서 차이점은 무엇입니까?

다른 컴파일러와 C++ 버전을 사용해 보았습니다. C++ 98의 이전 GCC 버전과 비슷하게 allocateTestString 유형으로 호출하지만 C++ 11 이상에서는 새로운 형식이 아닙니다. Clang도 allocate으로 전화하지 마십시오.

이렇게 다른 행동에 대한 설명을 보려면 궁금합니다.

할당 자 코드 : -이 내부적 작은 버퍼를 저장하는 수단

template< typename _T_ > 
struct TestAllocator 
{ 
    public: 

     typedef  _T_ value_type; 
     typedef  _T_ * pointer; 
     typedef const _T_ * const_pointer; 
     typedef  _T_ & reference; 
     typedef const _T_ & const_reference; 

     typedef std::size_t size_type; 
     typedef std::ptrdiff_t difference_type; 
     typedef std::true_type propagate_on_container_move_assignment; 
     typedef std::true_type is_always_equal; 

     template< class _U_ > 
     struct rebind 
     { 
      typedef TestAllocator<_U_> other; 
     }; 

     TestAllocator(void) noexcept 
     { 
      std::cout << "CTOR" << std::endl; 
     } 

     TestAllocator(const TestAllocator & other) noexcept 
     { 
      (void)other; 

      std::cout << "CCTOR" << std::endl; 
     } 

     template< class _U_ > 
     TestAllocator(const TestAllocator<_U_> & other) noexcept 
     { 
      (void)other; 

      std::cout << "CCTOR" << std::endl; 
     } 

     ~TestAllocator(void) 
     { 
      std::cout << "DTOR" << std::endl; 
     } 

     pointer address(reference x) const noexcept 
     { 
      return std::addressof(x); 
     } 

     pointer allocate(size_type n, std::allocator<void>::const_pointer hint = 0) 
     { 
      pointer p; 

      (void)hint; 

      std::cout << "allocate" << std::endl; 

      p = new _T_[ n ](); 

      if(p == nullptr) 
      { 
       throw std::bad_alloc() ; 
      } 

      return p; 
     } 

     void deallocate(_T_ * p, std::size_t n) 
     { 
      (void)n; 

      std::cout << "deallocate" << std::endl; 

      delete[] p; 
     } 

     const_pointer address(const_reference x) const noexcept 
     { 
      return std::addressof(x); 
     } 

     size_type max_size() const noexcept 
     { 
      return size_type(~0)/sizeof(_T_); 
     } 

     void construct(pointer p, const_reference val) 
     { 
      (void)p; 
      (void)val; 

      std::cout << "construct" << std::endl; 
     } 

     void destroy(pointer p) 
     { 
      (void)p; 

      std::cout << "destroy" << std::endl; 
     } 
}; 

template< class _T1_, class _T2_ > 
bool operator ==(const TestAllocator<_T1_> & lhs, const TestAllocator<_T2_> & rhs) noexcept 
{ 
    (void)lhs; 
    (void)rhs; 

    return true; 
} 

template< class _T1_, class _T2_ > 
bool operator !=(const TestAllocator<_T1_> & lhs, const TestAllocator<_T2_> & rhs) noexcept 
{ 
    (void)lhs; 
    (void)rhs; 

    return false; 
} 

답변

5

std::basic_string작은 버퍼 최적화(현 상황에서 일명 SBO 또는 SSO)을 사용하여 구현 될 수있다 작은 문자열에 대한 할당을 피할 수 있습니다. 이는 할당자가 사용되지 않는 이유 일 가능성이 큽니다.

"hello"을 긴 문자열 (32 자 이상)로 변경해보십시오. 아마 allocate이 호출됩니다.

는 또한 C++ 11 표준은 COW에서 구현 될 std::string을 금지하고 있습니다 (기록 중 복사) 패션 -이 문제에 대한 자세한 내용은 : "Legality of COW std::string implementation in C++11"


표준이 std::vector 금지 작은 버퍼 최적화를 사용하려면 : "May std::vector make use of small buffer optimization?"에 대한 자세한 정보가 있습니다.

+0

절대적으로 멋지고 정확합니다! 나는 그런 빠른 대답을 기대하지 않았지만, 대단히 감사합니다. :) SBO는 C++ 표준에서 명시 적으로 허용 되었습니까? 아니면 컴파일러가 수행하는 것입니까? 허용되는 경우, 어떤 섹션에서? 내 C++ 11 카피에서 검색하려고했지만 운이 없다. – Macmade

+1

@Macmade : ** 나는 이것에 대해 완전히 확신하지 못하지만, ** 나는 SBO가 허용 되나 요구되지는 않는다고 생각한다. . 따라서 표준에서 * "'std :: string'을 SBO"*로 구현해야합니다. * 표준과 호환되는 동안 구현 될 수있는 "명백한"최적화라고 가정합니다. –

+0

성능에 대해 완전히 이해하지만 예상되는 동작을 깨뜨릴 수도 있습니다 ... 이상한 표준에 대해 명시적인 것을 찾을 수 없습니다. – Macmade