Я пытался использовать собственный распределитель для std::vector<char>
но я заметил что std::vector
не требует / не использует какие-либо функции-члены из моего распределителя. Как это возможно?
#include <vector>
struct A : private std::allocator<char> {
typedef std::allocator<char> alloc;
using alloc::value_type;
using alloc::pointer;
using alloc::const_pointer;
using alloc::difference_type;
using alloc::size_type;
using alloc::rebind;
// member functions have been removed, since the program compiles without them
};
int main() {
std::vector<char, A> v;
v.resize(4000);
for (auto& c : v)
if (c)
return 1; // never happens in my environment
return 0; // all elements initialized to 0. How is this possible?
}
Я пробовал вышеупомянутую программу с онлайн-компилятором C ++ 11 (LiveWorkSpace), предоставляя g ++ 4.7.2, 4.8 и 4.6.3.
В принципе allocate()
, deallocate()
, construct()
а также destroy()
не определены в моем распределителе, но программа компилируется, и все элементы будут инициализированы в 0.
Стандартная библиотека GCC всегда перепривязывает предоставленный распределитель, поэтому внутри она делает что-то вроде этого (в C ++ 03):
typedef Alloc::template rebind<value_type>::other _Allocator_type;
(В C ++ 11 он использует allocator_traits
но в этом случае результат тот же.)
Затем вектор хранит объект этого типа внутри и использует его для всего (де) выделения.
Так как вы не определили rebind
шаблон члена в вашем распределителе, вы только что повторно объявили шаблон из базового класса, результат повторного связывания std::allocator<value_type>
а не ваш собственный тип. std::allocator
конечно, предоставляет все эти функции, так что именно они используются, независимо от того, определяете ли вы их по своему типу.
Вы можете исправить это, добавив это к вашему распределителю intead of using alloc::rebind;
чтобы vector
хранит и использует A
внутренне:
struct A : private std::allocator<char> {
template<typename U>
struct rebind {
typedef A other;
};
Нотабене это будет работать только для vector
, так как vector
Строго не нужно перепривязывать распределитель (пользователи должны создавать экземпляр шаблона с помощью allocator<value_type>
, но GCC vector
в любом случае перепривязывает, так что если пользователи создают vector<int, std::allocator<char>>
это все еще работает.) Для основанных на узле контейнеров, таких как std::set
ваш распределитель должен быть шаблоном, который может быть восстановлен, потому что контейнер должен распределять свои внутренние типы узлов, а не value_type
так нужно Alloc::rebind<internal_node_type>::other
быть действительным.
vector
свяжет распределитель Как вы приведете его в сферу из std::allocator
, A::rebind<T>::other
будет просто std::allocator<T>
, Так что все работает отлично.