私は物事がどのように機能するかを知りたいので、c++標準ライブラリを深く掘り下げてきました。先日、何かが起こった。
包含者(例:)はstd::vector<int, std::allocator<int> >
、割り当てに指定されたアロケータを使用する必要があります。具体的には、標準は次のように述べています。
23.1.8
この句で定義されているすべてのコンテナタイプのコピーコンストラクタは、それぞれの最初のパラメータからアロケータ引数をコピーします。これらのコンテナタイプの他のすべてのコンストラクタは、値型がコンテナの値型と同じアロケータであるAllocator&引数(20.1.5)を取ります。この引数のコピーは、各コンテナーオブジェクトの存続期間中に、これらのコンストラクターおよびすべてのメンバー関数によって実行されるメモリ割り当てに使用されます。この句で定義されているすべてのコンテナタイプで、メンバーget_allocator()は、コンテナの構築に使用されるAllocatorオブジェクトのコピーを返します。
また、標準の後半では、次のようになっています(いくつかの異なる場所で、1つを選択します)。
explicit deque(size_type n, const T& value = T(), const Allocator& = Allocator());
効果:指定されたアロケータを使用して、値のコピーがn個ある両端キューを作成します。
OK、それでは私の質問に移ります。
std::vector
例として、次のようなものを実装するための自然で効率的な方法を見てみましょう。
vector<T, A>::vector(const vector& x)
次のようになります。
template <class T, class A>
vector<T, A>::vector(const vector& x) {
pointer p = alloc_.allocate(x.size());
std::uninitialized_copy(x.begin(), x.end(), p);
first_ = p;
last_ = p + x.size();
end_ = p + x.size();
}
具体的には、メモリを割り当ててから、すべてのメンバーをコピーして配置します。new value_type[x.size()]
デフォルトでは、配列を上書きするためだけに配列を作成するため、このようなことをわざわざ行う必要はありません。
しかし、これはコピー構築を行うためにアロケータを使用しません...
次のようなループを手動で作成できます。
while(first != last) {
alloc_.construct(&*dest++, *first++);
}
しかし、それは無駄であり、ほぼ同じですstd::uninitialized_copy
。唯一の違いは、新しい配置の代わりにアロケータを使用することです。
したがって、標準に次のような(私には明らかなように見える)一連の関数がないことは見落としだと思いますか?
template <class In, class For, class A>
For uninitialized_copy(In first, In last, For dest, A &a);
template <class In, class Size, class For, class A>
For uninitialized_copy_n(In first, Size count, For dest, A &a);
template <class For, class T, class A>
void uninitialized_fill(For first, For last, const T& x, A &a);
template <class For, class Size, class T, class A>
void uninitialized_fill_n(For first, Size count, const T& x, A &a);
これらのタイプの関数は(手動で実装するのは簡単ですが...例外安全にしようとするまで)、独自のコンテナーなどを実装してコピー構造を効率的に使用したい場合は、かなり役立つと思います。アロケータを使用している間。
考え?