c ++ realloc та же самая гарантия указателя

0

Использование функции std :: realloc:

Если новый размер меньше, у него всегда есть гарантия, чтобы блок памяти находился в одном и том же положении и только уменьшал или мог иногда перемещать весь блок?

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

#include<cstdlib>
#include<iostream>
using namespace std;

int main(){
  //From 10,000,000 unsigned ints to 10 unsigned ints
  unsigned int * const array=new unsigned int[10000000];
  cout<<array<<endl;
  realloc(array,10*sizeof(unsigned int));
  cout<<array<<endl;
  delete array;
  return 0;
}
  • 5
    Вы не должны смешивать new() и realloc() .
  • 3
    Вы не можете перераспределить память, которая была выделена new .
Показать ещё 3 комментария
Теги:
realloc
dynamic-memory-allocation

4 ответа

2
Лучший ответ

Хотя я согласен с другими ответами в том, что вы не должны зависеть от этого, есть ответ, который можно найти в источнике glibc. (Я предполагаю, что вы используете glibc, так как вы еще не ответили на мой комментарий, спрашивая, какую библиотеку C вы используете)

EDIT: использование realloc в памяти, выделенное new, действительно запрещено, как упомянуто в других ответах.

Память, выделенная без внутреннего использования mmap

Если блок памяти не выделен с помощью mmap, __libc_realloc вызывает функцию _int_realloc, которая содержит следующий фрагмент кода:

if ((unsigned long) (oldsize) >= (unsigned long) (nb))
 {
   /* already big enough; split below */
   newp = oldp;
   newsize = oldsize;
 }

Это делает указатель на новую память равным указателю на старую память и соответственно устанавливает размер. Обратите внимание на split below комментария; старый блок памяти может быть изменен до требуемого размера, но не будет перемещен.


Память, выделенная внутренне с помощью mmap

Если память была внутренне распределена с помощью mmap, существует два способа изменения размера области памяти; mremap_chunk или серию вызовов в malloc, memcpy и free. Если функция mremap_chunk доступна, она используется вместо последней опции.

Память перераспределяется с использованием mremap_chunk

Функция mremap_chunk содержит этот фрагмент кода

/* No need to remap if the number of pages does not change.  */
if (size + offset == new_size)
    return p;

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

Память перераспределяется с использованием malloc, memcpy и free

Если mremap_chunk недоступен, источник __libc_realloc продолжается следующим образом:

/* Note the extra SIZE_SZ overhead. */
if (oldsize - SIZE_SZ >= nb)
    return oldmem;                         /* do nothing */

Если переменная oldsize минус размер блока больше или равна новому размеру, просто верните старую память.


Хорошо, тогда мы здесь. Во всех случаях glibc возвращает указатель на старую память, не перемещая ее (но, возможно, изменяя ее размер). Если вы используете glibc (и можете как-то гарантировать, что единственная библиотека C, с которой вы его используете, - glibc, и может гарантировать, что она не изменится в какой-то момент в будущем), вы можете полагаться на поведение, которое realloc не перемещает блок памяти, если запрашиваемый размер равен или меньше старого.

  • 1
    Очень зависящая от реализации и изменчивая информация. Имейте в виду, что даже если возвращенный указатель фактически совпадает с переданным указателем, все переменные, до сих пор хранящие старый указатель, впоследствии не определены. Это не теоретический момент, но он был продемонстрирован в дикой природе с использованием clang в блоге, который я недавно читал на UB. Мне просто жаль, что я потерял ссылку ...
  • 1
    Это кажется странным - позор, что вы потеряли ссылку, кажется интересным чтением. Но да, я согласен с вами; это больше интересовало то, как glibc справился с этим, чем с очень переносимой или практической информацией.
Показать ещё 3 комментария
3

Нет !! Если realloc преуспевает, старый указатель (если он не был nullpointer) неопределен.

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

realloc только имеет гарантии, явно указанные в стандарте:

  • Если возвращаемое значение не равно 0: новый указатель указывает на size байт по меньшей мере, первый мин (oldsize, newsize) равен переданному блоку.
  • Иначе, если size равен 0, ничего не произошло с переданным блоком.
  • Возможно, старый блок был освобожден или нет.

Мораль: никогда не передавайте размер 0 для realloc и используйте старый указатель для чего-либо (включая сравнение с новым указателем), если realloc не удалось (или вы передали нулевой указатель).

7.22.3.5 Функция realloc

#include <stdlib.h>
void *realloc(void *ptr, size_t size);

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

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

  • 0
    ОП не передает 0 в realloc, поэтому большая часть вашего ответа совершенно излишня при ответе на его вопрос. Звучит знакомо?
  • 0
    Ну, теперь вы достигли. Я даю полную картину, которая несколько отличается от осуждения его примера для иллюстрации его вопроса.
Показать ещё 3 комментария
2

C99 проект 7.20.3.4 гласит:

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

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

А также: не смешивайте new и realloc поскольку πάντα уже писал в комментариях.

0

Ничего не гарантировано в realloc. Это может уменьшить блок на месте, или он может выделить новый и скопировать данные. Это может также потерпеть неудачу.

Важный момент: realloc предназначен только для перераспределения памяти, ранее выделенной malloc. В вашем коде выше вы используете new которое не имеет эквивалента для перераспределения.

Также realloc фактически возвращает адрес нового блока памяти, поэтому в вашем коде выше вы будете: a) утечка этого и b) ссылка/освобождение потенциально уже выделенной памяти.

  • 0
    По его словам, он хочет знать, безопасно ли это (а это не так).
  • 0
    @Deduplicator: Ваша точка зрения?
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню