Ответ 1
Да, гарантируется стандартом C, если новый объект может быть выделен.
(C99, 7.20.3.4p2) "Функция realloc освобождает старый объект, на который указывает ptr, и возвращает указатель на новый объект, размер которого задан размером."
Давайте рассмотрим этот очень короткий фрагмент кода:
#include <stdlib.h>
int main()
{
char* a = malloc(20000);
char* b = realloc(a, 5);
free(b);
return 0;
}
После прочтения man-страницы realloc я не был полностью уверен, что вторая строка приведет к освобождению дополнительных байтов 19995. Чтобы процитировать справочную страницу: The realloc() function changes the size of the memory block pointed to by ptr to size bytes.
, но из этого определения я могу быть уверен, что остальное будет освобождено?
Я имею в виду, что блок, на который указывает b
, безусловно, содержит 5 свободных байтов, так ли будет достаточно, чтобы ленивый оператор-ассистент просто ничего не делал для строки realloc?
Примечание. Я использую распределитель, который освобождает 19 995 дополнительных байтов, как показано valgrind при комментировании строки free(b)
:
==4457== HEAP SUMMARY:
==4457== in use at exit: 5 bytes in 1 blocks
==4457== total heap usage: 2 allocs, 1 frees, 20,005 bytes allocated
Да, гарантируется стандартом C, если новый объект может быть выделен.
(C99, 7.20.3.4p2) "Функция realloc освобождает старый объект, на который указывает ptr, и возвращает указатель на новый объект, размер которого задан размером."
Да, если это удастся.
В вашем фрагменте кода показана хорошо известная, гнусная ошибка:
char* b = (char*) realloc(a, 5);
Если это удастся, память, ранее выделенная для a
, будет освобождена, а b
укажет на 5 байтов памяти, которые могут перекрывать или не перекрывать исходный блок.
Однако если сбой вызова, b
будет null
, но a
будет по-прежнему указывать на его исходную память, которая будет по-прежнему действительна. В этом случае вам нужно free(a)
освободить память.
Это еще хуже, если вы используете общую (опасную) идиому:
a = realloc(a, NEW_SIZE); // Don't do this!
Если вызов realloc
завершается с ошибкой, a будет null
, и его исходная память будет потеряна, что сделает ее безвозвратно потерянной до выхода вашей программы.
Это зависит от вашей реализации libc. Все следующее соответствует поведению:
Также возможно
В этом случае старые данные также останутся там, где они есть, что может привести к утечке памяти, например, если возвращаемое значение realloc()
перезаписывает единственную копию указателя на этот блок.
Разумная реализация libc будет использовать некоторую эвристику, чтобы определить, какое решение наиболее эффективно.
Также имейте в виду, что это описание находится на уровне реализации: Семантически, realloc()
всегда освобождает объект, пока распределение не прерывается.
Функция realloc имеет следующий контракт:
void * result = realloc (ptr, new_size)
Точные сведения о том, что происходит под капотом, являются специфичными для реализации - например, результат может быть равен ptr (но дополнительное пространство за пределами new_size больше не нужно касаться), и realloc может звонить бесплатно или может выполнять свои собственные внутренние свободное представление. Главное, что в качестве разработчика вы больше не несете ответственность за ptr, если realloc возвращает non-null, и вы по-прежнему несете ответственность за него, если realloc возвращает NULL.
Кажется маловероятным, что 19995 байт были освобождены. Скорее всего, что realloc заменил блок размером 20000 байтов на другой 5-байтовый блок, то есть блок размером 20000 байт был освобожден и был выделен новый 5-байтовый блок.