realloc
копирует все данные. Предполагая, что что-то еще попросит проблему производительности. Ситуации, когда realloc
могут избежать копирования, немногочисленны, и вы абсолютно не должны рассчитывать на них. Я видел более одной реализации realloc
, которая даже не беспокоится о внедрении кода, чтобы избежать копирования, потому что это не стоит усилий.
MMU не имеет к этому никакого отношения, потому что стоимость переназначения страниц памяти, выделяющих выделение, не окупается, пока вы не нажмете более двух страниц. Это основано на исследованиях, которые я прочитал 15 лет назад, и с тех пор копирование памяти стало быстрее, а управление памятью стало более дорогостоящим из-за систем MP. Это было также для схем с нулевой копией внутри ядра, без передачи служебных данных syscall, что является значительным и замедляет работу здесь. Это также потребовало бы, чтобы ваше распределение было идеально выровнено и разбросано, что еще больше снизило полезность реализации realloc
таким образом.
В лучшем случае realloc
может избежать копирования данных, если фрагмент памяти, который он расширил, не выделяется. Если realloc
- единственное, что вам может принести ваше приложение, но как только вы выделите немного фрагментации или других вещей, вам не повезло. Всегда предполагайте, что realloc равен malloc(new_size); memcpy(new, old, old_size); free(old);
.
Хорошая практика при работе с размерами массивов с realloc
- отслеживать, сколько элементов у вас есть в массиве и иметь отдельную емкость. Увеличьте емкость и realloc
только тогда, когда количество элементов попадает в емкость. Увеличьте емкость на 1.5x на каждом realloc (большинство людей делают 2x, это часто рекомендуется в литературе, но исследования показывают, что 2x вызывает очень плохие проблемы фрагментации памяти, а 1.5x почти так же эффективен и намного приятнее для памяти).Что-то вроде этого:
if (a->sz == a->cap) {
size_t ncap = a->cap ? a->cap + a->cap/2 : INITIAL_CAP;
void *n = realloc(a->a, ncap * sizeof(*a->a));
if (n == NULL)
deal_with_the_error();
a->a = n;
a->cap = ncap;
}
a->a[a->sz++] = new_element;
Это работает даже для первоначального выделения, если ваша структура, содержащая массив, инициализируется нулем.
1) C не C++ не C. Не используйте 'malloc' & co в C++. 2) Вы не можете расширять 'struct' на любом из этих языков во время выполнения. 3) Профилировали или сравнивали свой код? 4) C не имеет векторного типа/класса. 5) Не делайте преждевременных оптимизаций. – Olaf
@Olaf, пожалуйста, внимательно прочитайте мое сообщение: я не расширяю структуру, но я расширяю область памяти элементом, который является своего рода структурой. Тем не менее, все это не было моим вопросом ... – Elmi
«Я делаю это довольно часто, чтобы ** расширить доступную область памяти на один элемент ** (= конкретная структура)» - читается точно так же, как ваш код включает в себя дикое кастинг (который может легко привести к UB). – Olaf