標準テンプレート ライブラリのすべてのコンテナに共通するものは何ですか?これらには、デフォルトで std::allocator である型パラメーター Allocator があります。アロケーターの仕事は、その要素の寿命を管理することです。これは、その要素のメモリを割り当ておよび割り当て解除し、それらを初期化および破棄することを意味します。
この投稿では、標準テンプレート ライブラリのコンテナーについて書いていますが、これには std::string が含まれます。簡単にするために、コンテナという用語を両方に使用します。
std::allocator の何が特別なのですか?
一方では、std::allocator が std::vector または std::map のペアに要素を割り当てる場合、違いが生じます。
template< class T, class Allocator = std::allocator<T> > class vector; template< class Key, class T, class Compare = std::less<Key>, class Allocator = std::allocator<std::pair<const Key, T> > > class map;
一方、アロケーターは、その仕事を行うために一連の属性、メソッド、および関数を必要とします。
インターフェース
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | // Attributes value_type T pointer T* const_pointer const T* reference T& const_reference const T& size_type std::size_t difference_type std::ptrdiff_t propagate_on_container_move_assignment std::true_ty rebind template< class U > struct rebind { typedef allocator<U> other; }; is_always_equal std::true_type // Methods constructor destructor address allocate deallocate max_size construct destroy // Functions operator== operator!= |
つまり、std::allocator
内部クラス テンプレートの rebind (10 行目) は、これらの重要なメンバーの 1 つです。クラス テンプレートのおかげで、T 型の std::allocator を U 型に再バインドできます。std::allocate の中心は、allocate (17 行目) と deallocate (18 行目) の 2 つのメソッドです。どちらのメソッドも、オブジェクトがコンストラクト (20 行目) で初期化され、destroy (21 行目) で破棄されるメモリを管理します。メソッド max_size (19 行目) は、std::allocate がメモリを割り当てることができる型 T のオブジェクトの最大数を返します。
もちろん、std::allocator を直接使用することもできます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | // allocate.cpp #include <memory> #include <iostream> #include <string> int main(){ std::cout << std::endl; std::allocator<int> intAlloc; std::cout << "intAlloc.max_size(): " << intAlloc.max_size() << std::endl; int* intArray = intAlloc.allocate(100); std::cout << "intArray[4]: " << intArray[4] << std::endl; intArray[4] = 2011; std::cout << "intArray[4]: " << intArray[4] << std::endl; intAlloc.deallocate(intArray, 100); std::cout << std::endl; std::allocator<double> doubleAlloc; std::cout << "doubleAlloc.max_size(): " << doubleAlloc.max_size() << std::endl; std::cout << std::endl; std::allocator<std::string> stringAlloc; std::cout << "stringAlloc.max_size(): " << stringAlloc.max_size() << std::endl; std::string* myString = stringAlloc.allocate(3); stringAlloc.construct(myString, "Hello"); stringAlloc.construct(myString + 1, "World"); stringAlloc.construct(myString + 2, "!"); std::cout << myString[0] << " " << myString[1] << " " << myString[2] << std::endl; stringAlloc.destroy(myString); stringAlloc.destroy(myString + 1); stringAlloc.destroy(myString + 2); stringAlloc.deallocate(myString, 3); std::cout << std::endl; } |
プログラムで 3 つのアロケータを使用しました。 1 つは int 用 (11 行目)、もう 1 つは double 用 (26 行目)、もう 1 つは std::string 用 (31 行目) です。これらのアロケータはそれぞれ、割り当てることができる要素の最大数を認識しています (14、27、および 32 行目)。
次に、int のアロケーター:std::allocator
std::string アロケータの処理はより複雑です。 36 ~ 38 行目の stringAlloc.construct 呼び出しは、std::string の 3 つのコンストラクター呼び出しをトリガーします。 3 つの stringAlloc.destroy 呼び出し (42 行目から 44 行目) は反対のことを行います。最後 (34 行目) で myString のメモリが解放されます。
次に、プログラムの出力です。
C++17
C++17 では、std::allocator のインターフェースが非常に扱いやすくなっています。そのメンバーの多くは非推奨です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // Attributes value_type T propagate_on_container_move_assignment std::true_ty is_always_equal std::true_type // Methods constructor destructor allocate deallocate // Functions operator== operator!= |
しかし、重要な答えは、この投稿がまだ見つからないということです。
コンテナにアロケータが必要なのはなぜですか?
答えは 3 つあります。
<オール>次は?
メモリを要求するための戦略はどれですか?それが次の投稿で答えたい質問です。