Почему в распределителях C++ нет функции перераспределения?

В C стандартные функции обработки памяти malloc(), realloc() а также free(), Однако распределители stdlib в C++ только параллельны двум из них: функция перераспределения отсутствует. Конечно, было бы невозможно сделать точно так же, как realloc()потому что простое копирование памяти не подходит для неагрегированных типов. Но будет ли проблема, скажем, с этой функцией:

bool reallocate (pointer ptr, size_type num_now, size_type num_requested);

где

  • ptr ранее был выделен с тем же распределителем для num_now объекты;
  • num_requested > = num_now;

и семантика выглядит следующим образом:

  • если распределитель может расширить данный блок памяти в ptr от размера для num_now возражает против num_requested объекты, он делает это (оставляя дополнительную память неинициализированным) и возвращает true;
  • иначе он ничего не делает и возвращает false,

Конечно, это не очень просто, но распределители, как я понимаю, в основном предназначены для контейнеров, а код контейнеров обычно уже сложен.

Учитывая такую ​​функцию, std::vectorскажем, может вырасти следующим образом (псевдокод):

if (allocator.reallocate (buffer, capacity, new_capacity))
  capacity = new_capacity;     // That's all we need to do
else
  ...   // Do the standard reallocation by using a different buffer,
        // copying data and freeing the current one

Распределители, которые вообще не способны изменять размер памяти, могут просто реализовать такую ​​функцию безоговорочно return false;,

Есть ли так мало реализации распределителя с возможностью перераспределения, что не стоило бы беспокоиться об этом? Или есть какие-то проблемы, которые я упустил из виду?

5 ответов

Решение

От: http://www.sgi.com/tech/stl/alloc.html

Это, пожалуй, самое сомнительное дизайнерское решение. Вероятно, было бы немного более полезно предоставить версию reallocate, которая либо изменила бы размер существующего объекта без копирования, либо вернула NULL. Это сделало бы это непосредственно полезным для объектов с конструкторами копирования. Это также позволило бы избежать ненужного копирования в тех случаях, когда исходный объект не был полностью заполнен.

К сожалению, это запретило бы использование realloc из библиотеки C. Это, в свою очередь, усложнило бы многие реализации распределителя и усложнило бы взаимодействие с инструментами отладки памяти. Таким образом, мы решили против этой альтернативы.

На самом деле это конструктивный недостаток, на который указывает Александреску со стандартными распределителями (не оператор new[]/delete[], а то, что изначально были распределителями stl, например, для реализации std::vector).

Realloc может происходить значительно быстрее, чем malloc, memcpy и free. Однако, хотя размер фактического блока памяти можно изменить, он также может переместить память в новое место. В последнем случае, если блок памяти состоит из не-POD, все объекты должны быть уничтожены и построены с копированием после realloc.

Главной вещью, которую стандартная библиотека должна приспособить для этого как возможность, является функция перераспределения как часть открытого интерфейса стандартного распределителя. Класс, подобный std::vector, безусловно, мог бы использовать его, даже если реализация по умолчанию состоит в том, чтобы распределять блоки нового размера и освобождать старый. Это должна быть функция, которая способна разрушать и копировать объекты в памяти, хотя она не может обрабатывать память непрозрачным образом, если бы это делало это. Там есть небольшая сложность, которая потребует дополнительной работы с шаблоном, возможно, поэтому она была исключена из стандартной библиотеки.

std::vector<...>:: reserve недостаточно: он обращается к другому случаю, когда можно ожидать размер контейнера. Для списков действительно переменного размера решение realloc может сделать смежные контейнеры, такие как std::vector, намного быстрее, особенно если оно может иметь дело со случаями realloc, когда блок памяти был успешно изменен без перемещения, в этом случае он может опустить вызывающую копию конструкторы и деструкторы для объектов в памяти.

То, что вы просите, по сути, что vector::reserve делает. Без семантики перемещения объектов невозможно перераспределить память и перемещать объекты без копирования и уничтожения.

Из-за объектно-ориентированной природы C++ и включения различных стандартных типов контейнеров, я думаю, просто, что меньше внимания уделялось управлению памятью направления, чем в C. Я согласен, что бывают случаи, когда realloc() будет полезен, но давление для исправления этого минимально, поскольку почти все получающиеся в результате функциональные возможности могут быть получены с использованием контейнеров.

Я полагаю, что это одна из тех причин, когда Бог ошибся, но мне было просто лень писать в комитет по стандартам.

Должен был быть realloc для размещения массива:

p = renew(p) [128];

или что-то типа того.

Другие вопросы по тегам