2008-10-19 2 views
6

Как я понимаю, когда просят резервировать больший блок памяти, функция перераспределить() будет делать один из трех вещей:Определение перераспределить поведения() перед вызовом его

 
if free contiguous block exists 
    grow current block 
else if sufficient memory 
    allocate new memory 
    copy old memory to new 
    free old memory 
else 
    return null 

РОСТОМ текущий блок - очень дешевая операция, так что это поведение, которое я бы хотел использовать. Однако, если я перераспределяю память, потому что хочу (например) вставить символ в начале существующей строки, я не хочу, чтобы realloc() копировал память. Я закончу копирование всей строки с помощью realloc(), а затем снова скопирую ее вручную, чтобы освободить первый элемент массива.

Можно ли определить, что будет делать realloc()? Если да, можно ли достичь кросс-платформенного подхода?

+1

Последнее из ваших 3 случаев неверно, realloc вернет нулевой указатель, если недостаточно памяти, а не указатель, который вы передали. – 2008-10-19 14:19:49

+0

Как сказал Роберт Гэмбл - realloc() возвращает NULL без памяти. – 2008-10-19 14:43:09

+0

Спасибо, исправлены псевдокоды. – Ant 2008-10-19 14:57:21

ответ

7

realloc() «s поведение, скорее всего, в зависимости от его конкретной реализации. И, основывая свой код на этом, будет ужасный взлом, который, мягко говоря, нарушает инкапсуляцию.

Лучшее решение для вашего конкретного примера:

  1. Найти размер текущего буфера
    • выделить новый буфер (с malloc()), больше, чем предыдущий
    • Скопируйте префикс для нового буфера
    • Скопируйте строку в предыдущем буфере в новый буфер, начиная с префикса
    • Выпуск предыдущей буфер
0

No - и если вы думаете об этом, он не может работать. Между вами, проверяя, что он собирается делать и на самом деле это делает, другой процесс может выделять память. В многопоточном приложении это не сработает. Между тем, проверяя, что он собирается делать и на самом деле делает это, другой поток может выделять память.

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

0

Я не думаю, что это возможно на кросс-платформенном пути. Here код для ulibc реализации, которые могли бы дать вам понять, как сделать тир платформы зависимый путь, на самом деле это лучше, чтобы найти источник GLibC но один был на вершине поиска Google :)

0

Если obstacks хороший матч для ваших потребностей распределения памяти, вы можете использовать их функциональность fast growing. Замки - это функция glibc, но они также доступны в библиотеке libiberty, которая довольно портативна.

2

Как отмечено в комментариях, случай 3 в вопросе (без памяти) неверен; realloc() вернет NULL, если нет доступной памяти [вопрос теперь исправлен].

Steve McConnell в «Code Complete» указывает, что если вы сохраните возвращаемое значение от realloc() в единственной копии исходного указателя, когда realloc() не удался, вы только что просочились в память.То есть:

void *ptr = malloc(1024); 
... 
if ((ptr = realloc(ptr, 2048)) == 0) 
{ 
    /* Oops - cannot free original memory allocation any more! */ 
} 

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

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

1

Хранение вашей строки назад поможет?

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

Используя этот метод, вы также можете правильно обосновать свою строку в буфере, так что легко добавлять символы в начало.

0

Почему бы не сохранить некоторые пустое пространство буфера в левой части строки, например:

char* buf = malloc(1024); 
char* start = buf + 1024 - 3; 
start[0]='t'; 
start[1]='o'; 
start[2]='\0'; 

Чтобы добавить «на» в начале вашей строки, чтобы сделать его «на \ 0»:

start-=2; 
if(start < buf) 
    DO_MEMORY_STUFF(start, buf);//time to reallocate! 
start[0]='o'; 
start[1]='n'; 

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

Если вам нужно делать вставки как в начале, так и в конце, просто выделите некоторое пространство на обоих концах; Очевидно, что вставки в середине все равно нуждаются в перетасовке элементов.

0

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

Смежные вопросы