Is there a way to either query what would realloc do, or prevent it from copying all memory on Windows and Linux?

Viewed 102

I'm implementing a container similar to std::vector from C++. It has a buffer with associated capacity (memory which is reserved for this container) and size (actual size of the container).

When the user adds elements and size needs to exceed the capacity, I use realloc for the new capacity.

There is a reserve function for the container which sets the capacity in case the user knows it beforehand and doesn't want to risk allocating memory when filling the container with data.

Thus invariants might exist where the size is small (say zero) and the capacity is big (say 1MB). Then if the user calls reserve(even_bigger_capacity), what am I supposed to do?

I can just call realloc, but if realloc does end up allocating a new memory block, it will copy 1MB of useless bytes into it.

I can have a constant: WASTEFUL_COPY_BYTES and check capacity - size > WASTEFUL_COPY_BYTES, and manually call malloc and memcpy and copy only what's needed, in case it's true, and only call realloc if the difference is small, but in this case I'm missing opportunities to use realloc where it would return the same address.

Basically I need something like bool try_realloc(void *old_addr, size_t new_size) which would return true if realloc would return the same address, but won't try to allocate a new block and copy stuff.

...or something like void* part_realloc(void* old_addr, size_t new_size, size_t relevant_size) which would only copy relevant_size bytes into the new block, if it ends up allocating one.

I'm sure there are platform-specific ways of implementing both of these functions, so my question is: is there a library with such functions which works on major platforms or, if not, how would I go about implementing something like this at least for Windows and Linux?

1 Answers

So, on Windows, _expand is exactly what I need.

On Linux, things don't look as simple. I'll need to deep dive in glibc. Perhaps malloc_usable_size will be helpful.

edit: It's not (well not very much. It returns too few bytes more than the allocation size). It seems there is no way to implement this with glibc's public interface. The only way is to look through glibc's code, duplicate the data structures and use the chunk before the returned memory block, which is a Bad Idea™

I'll report further findings here unless someone provides a better answer in the meantime

Related