является ли uninitialized_copy / fill (во первых, в последних, для dest, A & a) упущением в стандарте c ++? - PullRequest
3 голосов
/ 16 марта 2012

Мне нравится знать, как все работает и, как таковая, углубилась в стандартную библиотеку c ++. Что-то произошло со мной на днях.

Требуется, чтобы в контейнерах (например: std::vector<int, std::allocator<int> >) использовался распределитель, указанный для распределений. В частности, стандарт гласит:

23.1.8

Копировать конструкторы для всех типов контейнеров, определенных в этом разделе. аргумент распределителя из их соответствующих первых параметров. Все другие конструкторы для этих типов контейнеров принимают Allocator & аргумент (20.1.5), распределитель, тип значения которого совпадает с тип значения контейнера. Копия этого аргумента используется для любой памяти распределение выполняется этими конструкторами и всеми членами функции, в течение времени жизни каждого объекта контейнера. В целом типы контейнеров, определенные в этом пункте, член get_allocator () возвращает копию объекта Allocator, использованного для создания контейнер.

Также позже в стандарте говорится (в нескольких разных местах, но я выберу один) такие вещи:

explicit deque(size_type n, const T& value = T(), const Allocator& = Allocator());

Эффекты: создает деку с n копиями значения, используя указанный распределитель.

Хорошо, так на мой вопрос.

Давайте возьмем 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);

Я бы предположил, что эти типы функций (даже если их тривиально реализовать вручную ... пока вы не попытаетесь сделать их безопасными исключениями) оказались бы весьма полезными, если бы люди захотели реализовать свои собственные контейнеры и тому подобное и эффективно использовать построения копии при использовании распределителей.

Мысли

Ответы [ 2 ]

2 голосов
/ 16 марта 2012

Я не уверен, что мы могли бы назвать это "недосмотром", по сути.

Нет, вы не можете предоставить свой собственный распределитель для этих специализированных алгоритмов. Но есть и другие вещи, которых в стандарте тоже нет.

@ MarkB указывает на очень вескую причину того, что стандарт не должен делать это (что диапазон не знает распределителя контейнера). Я бы сказал, что это просто неотъемлемое ограничение.

Вы всегда можете заново изобрести uninitialized_copy для своих нужд, зная, каким должен быть распределитель. Это просто двухстрочный цикл for.

1 голос
/ 16 марта 2012

Если бы эти функции были свободными, я не вижу способа, чтобы компилятор мог обнаружить несоответствия распределителя, так как тип распределителя не сохраняется итератором. Это, в свою очередь, может привести к множеству труднодоступных проблем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...