First, the deeper problem: if you're using C++, why are you using realloc? This is C-style memory management, which certainly has its place, even in modern C++ code...but very very rarely. In almost all cases, it's better to use std::shared_ptr or std::unique_ptr.
That said, realloc is perhaps one of the few reasons to use C-style allocation, but only if you need it for optimization purposes. (Remember, premature optimization is the root of all evil!)
For the rest of the answer, I'll assume you have a very good, well-reasoned argument for using realloc and C-style memory management in C++. If you don't, stop right now and rethink your code in terms of modern C++ memory management. It's treacherous using free/malloc/calloc/realloc, and even new/delete, without having a very clear and well-defined architectural reason.
realloc comes from the C language, so the best way to find out what it does, and if there is any potential undefined behavior, is to check the official standard.
(You can purchase the official standard, but if you're anything like me, you don't want to drop nearly a hundred quid just to read the thing; you can just read the final draft instead, which is pretty much the same but for a few minor corrections. You can find the official PDF here.)
So, here's a few important pieces from 7.22.3.5...
The realloc function deallocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by size.
There's the answer to your first question. realloc will free the old pointer, the same as free does. Thus, if you access/dereference that freed pointer after calling realloc on it, the behavior is undefined. A segfault is just one possible form of undefined behavior.
The contents of the new object shall be the same as that of the old object prior to deallocation, up to the lesser of the new and old sizes. Any bytes in the new object beyond the size of the old object have indeterminate values.
This is also an area of potential weirdness! If you realloc with a larger size, the new space might contain literally anything. In other words, if you start with an array of four integers, and realloc it to an array of eight integers, indices [3] through 7 is not guaranteed to be set to 0, but could be anything. Thus, you'll have to be careful to initialize the new values in those spaces before reading from them.
If ptr is a null pointer, the realloc function behaves like the malloc function for the specified size.
From this, we know that passing a null pointer to realloc is not going to be a problem; it'll just behave like malloc would. Good to know.
Otherwise, if ptr does not match a pointer earlier returned by a memory management function, or if the space has been deallocated by a call to the free or realloc function, the behavior is undefined.
Don't pass a dangling or wild pointer to realloc; that would result in undefined behavior, such as (but not necessarily being) a segmentation fault.
If memory for the new object cannot be allocated, the old object is not deallocated and its value is unchanged.
This is interesting! If you pass a pointer to realloc, but it cannot reallocate for any reason, it will not free the pointer. How do we know if it could reallocate? Read on...
The realloc function returns a pointer to the new object (which may have the same value as a pointer to the old object), or a null pointer if the new object could not be allocated.
If there's a problem allocating, realloc will return a null pointer, indicating that the pointer we passed in was not freed, and thus is still valid and safe to use.
Also, important note about assumptions here: the new, reallocated pointer might actually be the same as the old pointer. Or it might not.
All that said, you should use realloc with the following assumptions:
You can pass a valid pointer, or a null pointer, to realloc.
After reallocation, any non-null pointer passed to realloc will be freed.
If realloc returns a null pointer, it couldn't reallocate, and you can keep using the pointer you passed in (it was not freed.)
If realloc returns a pointer, it's valid, regardless of whether it seems to be the same as the one you passed in.
First, the deeper problem: if you're using C++, why are you using
realloc
? This is C-style memory management, which certainly has its place, even in modern C++ code...but very very rarely. In almost all cases, it's better to usestd::shared_ptr
orstd::unique_ptr
.That said,
realloc
is perhaps one of the few reasons to use C-style allocation, but only if you need it for optimization purposes. (Remember, premature optimization is the root of all evil!)For the rest of the answer, I'll assume you have a very good, well-reasoned argument for using
realloc
and C-style memory management in C++. If you don't, stop right now and rethink your code in terms of modern C++ memory management. It's treacherous usingfree/malloc/calloc/realloc
, and evennew/delete
, without having a very clear and well-defined architectural reason.realloc
comes from the C language, so the best way to find out what it does, and if there is any potential undefined behavior, is to check the official standard.(You can purchase the official standard, but if you're anything like me, you don't want to drop nearly a hundred quid just to read the thing; you can just read the final draft instead, which is pretty much the same but for a few minor corrections. You can find the official PDF here.)
So, here's a few important pieces from 7.22.3.5...
There's the answer to your first question.
realloc
will free the old pointer, the same asfree
does. Thus, if you access/dereference that freed pointer after callingrealloc
on it, the behavior is undefined. A segfault is just one possible form of undefined behavior.This is also an area of potential weirdness! If you realloc with a larger size, the new space might contain literally anything. In other words, if you start with an array of four integers, and realloc it to an array of eight integers, indices [3] through 7 is not guaranteed to be set to
0
, but could be anything. Thus, you'll have to be careful to initialize the new values in those spaces before reading from them.From this, we know that passing a null pointer to
realloc
is not going to be a problem; it'll just behave likemalloc
would. Good to know.Don't pass a dangling or wild pointer to
realloc
; that would result in undefined behavior, such as (but not necessarily being) a segmentation fault.This is interesting! If you pass a pointer to
realloc
, but it cannot reallocate for any reason, it will not free the pointer. How do we know if it could reallocate? Read on...If there's a problem allocating,
realloc
will return a null pointer, indicating that the pointer we passed in was not freed, and thus is still valid and safe to use.Also, important note about assumptions here: the new, reallocated pointer might actually be the same as the old pointer. Or it might not.
All that said, you should use
realloc
with the following assumptions:realloc
.realloc
will befree
d.realloc
returns a null pointer, it couldn't reallocate, and you can keep using the pointer you passed in (it was notfree
d.)realloc
returns a pointer, it's valid, regardless of whether it seems to be the same as the one you passed in.Thanks for the response. I solved the problem in a very simple manner.
Your detailed reponse really helped me think in the right direction.