Использование функции 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;
}
Хотя я согласен с другими ответами в том, что вы не должны зависеть от этого, есть ответ, который можно найти в источнике 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
не перемещает блок памяти, если запрашиваемый размер равен или меньше старого.
glibc
справился с этим, чем с очень переносимой или практической информацией.
Нет !! Если realloc
преуспевает, старый указатель (если он не был nullpointer) неопределен.
Кроме того, не смешивайте несовместимые функции управления памятью (предполагайте несовместимость, если не указано иное).
realloc
только имеет гарантии, явно указанные в стандарте:
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
возвращает указатель на новый объект (который может иметь то же значение, что и указатель на старый объект), или нулевой указатель, если новый объект не может быть выделен.
C99 проект 7.20.3.4 гласит:
[# 4] Функция realloc возвращает указатель на новый объект (который может иметь то же значение, что и указатель на старый объект), или нулевой указатель, если новый объект не может быть выделен.
Вы не должны этого допускать.
А также: не смешивайте new
и realloc
поскольку πάντα уже писал в комментариях.
Ничего не гарантировано в realloc
. Это может уменьшить блок на месте, или он может выделить новый и скопировать данные. Это может также потерпеть неудачу.
Важный момент: realloc
предназначен только для перераспределения памяти, ранее выделенной malloc
. В вашем коде выше вы используете new
которое не имеет эквивалента для перераспределения.
Также realloc
фактически возвращает адрес нового блока памяти, поэтому в вашем коде выше вы будете: a) утечка этого и b) ссылка/освобождение потенциально уже выделенной памяти.
new()
иrealloc()
.new
.