Search code examples
c++dynamic-memory-allocationrealloc

c++ realloc same pointer warranty


Using the std::realloc function:

If the new size is smaller, does it always have warranty to keep the memory block on the same position and only make it smaller, or it can move sometimes the whole block?

The reason to ask this, is that we'are writing a large and very hard code, and it is useful to make read only all the variables we need to leave unchanged, to obtain compiler's errors, when we try to change the wrong variable.

#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;
}

Solution

  • Although I agree with the other answers in that you should not depend on it, there is an answer to be found in the glibc source. (I am assuming that you are using glibc, as you have not (yet) answered my comment asking which C library you are using)

    EDIT: Using realloc on memory allocated by new is indeed disallowed, as other answers have mentioned.

    Memory allocated without internally using mmap

    If a block of memory is not allocated with mmap, __libc_realloc calls the _int_realloc function, which contains the following snippet of code:

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

    This makes the pointer to the new memory equal the pointer to the old memory and sets the size accordingly. Note the split below comment; the old memory block may be resized to the requested size, but is not moved.


    Memory allocated internally using mmap

    If the memory was internally allocated using mmap, there are two ways of resizing the memory area; mremap_chunk or a series of calls to malloc, memcpy and free. If the mremap_chunk function is available, it is used instead of the latter option.

    Memory reallocated using mremap_chunk

    The function mremap_chunk contains this snippet of code

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

    If the number of pages does not change from the old size to the new size, there is no need to remap and the old pointer is returned.

    Memory reallocated using malloc, memcpy and free

    If mremap_chunk is not available, the __libc_realloc source continues with the following:

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

    If the oldsize variable minus the chunk size is more than or equal to the new size, just return the old memory.


    Well then, here we are. In all cases, glibc returns a pointer to the old memory, not moving it (but possibly resizing it). If you are using glibc (and can somehow guarantee that the only C library you are using it with is glibc, and can guarantee that it won't change at some point in the future), you are able to rely on the behavior that realloc does not move a block of memory if the requested size is equal to or less than the old size.