Почему вектор указателя не имеет "пользовательского удалителя", если такая вещь существует
Потому что такая вещь не существует и не может существовать.
Распределитель, предоставленный контейнеру, существует для выделения памяти для контейнера и (необязательно) создает / уничтожает объекты в этом контейнере.A vector<T*>
- контейнер указателей;следовательно, распределитель выделяет память для указателя и (необязательно) создает / уничтожает указатели.Он не несет ответственности за содержимое указателя: объект, на который он указывает.Это домен пользователя для предоставления и управления.
Если распределитель берет на себя ответственность за уничтожение объекта, на который указывает объект, то он должен также логически нести ответственность за создание объекта, на который указываетда?В конце концов, если этого не произойдет, и мы скопируем такой vector<T*, owning_allocator>
, каждая копия будет ожидать уничтожения объектов, на которые указывают.Но так как они указывают на одни и те же объекты (копирование vector<T>
копирует T
s), вы получаете двойное уничтожение.
Поэтому, если owning_allocator::destruct
собирается удалить память, owning_allocator::construct
должен также создать объект, на который указывают.
Итак ... что это делает:
vector<T*, owning_allocator> vec;
vec.push_back(new T());
Видите проблему?allocator::construct
не может решить, когда создавать T
, а когда нет.Он не знает, вызывается ли он из-за операции vector
копирования или потому, что push_back
вызывается с созданным пользователем T*
.Все, что он знает, это то, что он вызывается со значением T*
(технически это ссылка на T*
, но это не имеет значения, поскольку он будет вызываться с такой ссылкой в обоих случаях).
Поэтомулибо он 1) размещает новый объект (инициализируется с помощью копии из указанного ему указателя), либо 2) копирует значение указателя.А поскольку он не может определить, какая ситуация находится в игре, он всегда должен выбирать один и тот же вариант.Если он # 1, то приведенный выше код является утечкой памяти, потому что вектор не сохранил new T()
, и никто больше не удалил его.Если он # 2, то вы не можете скопировать такой вектор (и история о внутреннем перераспределении векторов одинаково туманная).
То, что вы хотите, невозможно.
A vector<T>
является контейнером T
s, каким бы T
ни был.T
трактуется как есть;любое значение , означающее этого значения, остается за пользователем.И семантика владения является частью этого значения.
T*
не имеет семантики владения, поэтому vector<T*>
также не имеет семантики владения.unique_ptr<T>
имеет семантику владения, поэтому vector<unique_ptr<T>>
также имеет семантику владения.
Вот почему Boost имеет ptr_vector<T>
, то есть явно класс в векторном стиле, который специально содержит указатели наT
s.Из-за этого у него слегка измененный интерфейс;если вы вручите ему T*
, он знает, что принимает T*
, и уничтожит его.Если вы передаете ему T
, то он выделяет новый T
и копирует / перемещает значение во вновь выделенное T
.Это другой контейнер, с другим интерфейсом и другим поведением;следовательно, он заслуживает другого типа от vector<T*>
.