Realloc гарантированно будет на месте, когда буфер сокращается? - PullRequest
10 голосов
/ 02 июля 2010

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

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

всегда выдаст new_ptr == old_ptr, если new_size

Я смотрю на перераспределение массивов типов данных, отличных от 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
}

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

Ответы [ 5 ]

8 голосов
/ 02 июля 2010

номер

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

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


С c99:

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

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

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


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

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

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

6 голосов
/ 02 июля 2010

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

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

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

3 голосов
/ 02 июля 2010

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

РЕДАКТИРОВАТЬ:

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

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

2 голосов
/ 02 июля 2010

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

1 голос
/ 02 июля 2010

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

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