2017-03-09 81 views
2

我最近對std::allocator有一些興趣,認爲它可能解決我在C++代碼上做出的一些設計決策時遇到的問題。std :: allocator上的Rambling

現在我已閱讀了一些關於它的文檔,觀看了一些視頻,如Andrei Alexandrescu's one at CppCon 2015,我現在基本上明白我不應該使用它們,因爲它們不是按照我認爲分配器可以工作的方式工作。

這就是說,在實現這個之前,我寫了一些測試代碼來了解std::allocator的自定義子類是如何工作的。

顯然,沒有按預期工作...:)

所以,問題不在於如何分配器應在C++中使用,但我只是好奇,確切的知道爲什麼我的測試代碼(提供下面)不起作用。
不是因爲我想使用自定義分配器。只是好奇,看到確切的原因...

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; 
} 

在這個問題的最後提供了TestAllocator的完整代碼。

在這裏,我只是使用我的自定義分配器與一些std::basic_stringstd::vector

隨着std::basic_string,我可以看到我的分配器的實例被實際創建,但沒有一種方法被稱爲...
所以它只是看起來像它根本不使用。

但與std::vector,我自己的allocate方法實際上被調用。

那麼爲什麼這裏有區別?

我嘗試過使用不同的編譯器和C++版本。 看起來像舊的GCC版本,使用C++ 98,在我的TestString類型上調用allocate,但使用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個標準禁止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

相關問題