Гарантируется ли realloc на месте, когда буфер сокращается?

Есть ли какие-либо гарантии, что realloc() всегда будет сжимать буфер на месте? Чтобы следующее:

new_ptr = (data_type *) realloc(old_ptr, new_size * sizeof(data_type));

всегда будет давать new_ptr == old_ptr, если new_size < old_size (за исключением, конечно, new_size == 0). Кажется разумным (для меня), что он будет работать таким образом, но было любопытно, соблюдал ли стандарт его.

Я рассматриваю перераспределение массивов типов данных, отличных от POD, и, если вышеприведенное поведение было гарантировано, было подумано, что следующая стратегия может по крайней мере обеспечить эффективное "сжатие":

if (new_size > old_size)
{
    // malloc() a new buffer
    // use placement copy constructor to copy old objects over
    // free() old buffer
}
else
if (new_size < old_size)
{
    // explicit destruction of unneeded objects
    // realloc() buffer
}

Я ожидаю, что "усадка" на месте будет надежной, даже если тип данных имеет собственные ссылки/указатели или что-то еще...

Ответ 1

Нет.

Это. Ничто из этого "это не может работать в некоторых архитектурах" или "это должно, основываясь на опыте". В стандарте четко указано, что адрес может измениться, поэтому полагайтесь на это и не более того. В любом случае, вы спросили, было ли это гарантировано - ответ, который определенно нет (а).

С точки зрения кодирования по стандарту: делать или не делать. Здесь нет "попробовать" :-)


С c99:

Функция realloc освобождает старый объект, на который указывает ptr и возвращает указатель на новый объект, размер которого определяется size. Содержимое нового объекта должно быть таким же, как и у старого объекта до освобождения, до меньшего из нового и старого размеров. Любые байты в новом объекте, превышающие размер старого объекта, имеют неопределенные значения.

Если ptr является нулевым указателем, функция realloc ведет себя как функция malloc для указанного размера. В противном случае, если ptr не соответствует указателю, ранее возвращенному функцией calloc, malloc или realloc, или если пространство было освобождено при вызове функции free или realloc, поведение не определено. Если память для нового объекта не может быть выделена, старый объект не освобождается и его значение не изменяется.

Функция realloc возвращает указатель на новый объект (который может иметь то же значение, что и указатель на старый объект), или нулевой указатель, если новый объект не может быть выделен.


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

Если у вас есть разные пулы для распределений разных размеров (например, которые могут использовать разные стратегии распределения), может иметь смысл переместить данные в пул для меньших распределений. Прирост эффективности, который вы получаете от отдельных пулов, может перевесить выигрыш от оставления памяти на месте.

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

Ответ 2

Нет. Вы не должны полагаться на это.

Согласно спецификации 7.20.3.4/4:

Функция realloc возвращает указатель к новому объекту (который может иметь то же значение, что и указатель на старый объект) или нулевой указатель если новый объект не может быть выделены.

Ответ 3

В общем случае, но это не гарантировано (все зависит от вашей архитектуры). Итак, Вы не должны полагаться на это при таком поведении

EDIT:

ссылка: http://opengroup.org/onlinepubs/007908775/xsh/realloc.html

После успешного завершения с размером не равный 0, realloc() возвращает указатель на (возможно, перемещенный) выделенное пространство.

Ответ 4

Некоторые распределители используют стратегию "bucketizing", где распределения, размером от, скажем, от 2 ^ 3 до 2 ^ 4, переходят в одно и то же поле распределения. Это, как правило, предотвращает экстремальные случаи фрагментации памяти, когда многие небольшие распределения, распределенные по куче, препятствуют успешному выполнению больших распределений. Очевидно, что в таком кучевом менеджере уменьшение размера выделения может привести к другому ведру.

Ответ 5

Нет, такой гарантии нет. Реализации realloc могут просто сжать буфер на месте, но они не ограничены этим.