Вы должны думать о realloc
как о работе следующим образом:
void *realloc(void *oldptr, size_t newsize)
{
size_t oldsize = __extract_size_of_malloc_block(oldptr);
void *newptr = malloc(newsize);
if (!newptr)
return 0;
if (oldsize > newsize)
oldsize = newsize;
memcpy(newptr, oldptr, oldsize);
free(oldptr);
return newptr;
}
Реализация может быть в состоянии выполнять конкретные случаи более эффективно, чем эта, но реализация, которая работает точно так, как показано, является на 100% правильной. Это означает, что realloc(ptr, newsize)
может потерпеть неудачу в любое время malloc(newsize)
потерпит неудачу; в частности, может произойти сбой , даже если вы сокращаете выделение .
Теперь в современных настольных системах есть веские основания не пытаться восстанавливаться после сбоев malloc
, а вместо этого включать malloc
в функцию (обычно называемую xmalloc
), которая немедленно завершает программу, если malloc
терпит неудачу; естественно, тот же аргумент применим к realloc
. Дело в том:
- Настольные системы часто работают в режиме «overcommit», когда ядро с радостью раздаст больше адресного пространства, чем может быть поддержано RAM + swap, при условии, что программа фактически не собирается использовать все это. Если программа попытается использовать все это, она будет принудительно завершена. В таких системах malloc завершится с ошибкой только в том случае, если вы исчерпали адресное пространство , что маловероятно в 32-разрядных системах и почти невозможно в 64-разрядных системах.
- Даже если вы не находитесь в режиме overcommit, существует вероятность того, что настольная система имеет так много оперативной памяти и доступно для подкачки, что задолго до того, как вы вызовете сбой
malloc
, пользователю надоест его диск-диск и принудительно завершить вашу программу.
- Нет практического способа проверить восстановление после сбоя выделения; даже если бы у вас была библиотека подкладок, которая могла бы точно контролировать, какие вызовы на
malloc
были неудачными (такие подкладки в лучшем случае сложно, в худшем случае невозможно создать, в зависимости от ОС), вам придется протестировать порядок 2 N. шаблоны ошибок, где N - количество вызовов malloc в вашей программе.
Аргументы 1 и 2 не применяются к встроенным или мобильным системам (пока!), Но аргумент 3 все еще действует там.
Аргумент 3 применяется только к программам, в которых ошибки распределения должны проверяться и распространяться на каждом сайте вызовов. Если вам так повезло, что вы используете C ++ так, как он предназначен (т.е. с исключениями), вы можете положиться на компилятор, который создаст для вас пути восстановления после ошибок, поэтому нагрузка на тестирование будет значительно снижена. И на любом языке более высокого уровня, который стоит использовать в настоящее время, у вас есть и исключения, и сборщик мусора, что означает, что вы не могли бы беспокоиться о сбоях выделения, даже если бы захотели.