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

В C стандартными функциями обработки памяти являются malloc(), realloc() и free(). Однако С++ stdlib-распределители только параллельны двум из них: нет функции перераспределения. Конечно, было бы невозможно сделать то же самое, что и 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 all we need to do
else
  ...   // Do the standard reallocation by using a different buffer,
        // copying data and freeing the current one

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

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

Ответ 1

С: http://www.sgi.com/tech/stl/alloc.html

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

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

Ответ 2

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

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

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

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

Ответ 3

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

Ответ 4

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

Ответ 5

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

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

p = renew(p) [128];

или что-то в этом роде.