2017-03-09 3 views
2

私は最近、std::allocatorに興味を持ち、C++コードに関する設計上の問題を解決するかもしれないと考えました。std :: allocatorに乗って

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++バージョンを試しました。 C++ 98の古いGCCバージョンのように見えますが、私の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が呼び出されます。"Legality of COW std::string implementation in C++11"


標準std::vectorを禁止:この問題の詳細について -

はまたファッションC++ 11標準は、COW (コピーオンライト)に実装されるstd::stringを禁じていることに注意してください小さなバッファの最適化を利用する:詳細は、この質問で見つけることができます:"May std::vector make use of small buffer optimization?"

+0

絶対に素晴らしいです!私はそのような迅速な答えを期待していないが、非常にありがとう。 :) SBOはC++標準によって明示的に許可されていますか、それとも単にコンパイラが行うものですか?許可されている場合は、どのセクションですか?私のC++ 11のコピーでそれを検索しようとしましたが、幸運はありません。 – Macmade

+1

@Macmade:**私はこれについて完全にはわかりませんが、**私は** SBOは許可されていますが、 。したがって、標準で* "' std :: string'をSBO "*で実装する必要があるようなものは見つからないでしょう - 標準に準拠して実装できる"明白な "最適化だと思います。 –

+0

パフォーマンスには全く意味がありますが、期待される動作を破る可能性があります...奇妙なことに、私は標準で明示的に何かを見つけることができません。 – Macmade

関連する問題