13

In C, we have malloc(), free(), and realloc(). In C++ we have new(), delete() and their array versions. Is there a C++ realloc function? I'm implementing some low level stuff in embedded land and just realized there was no realloc function to pair up with the C++ functions and wanted to make sure I wasn't missing anything. I'm guessing "placement new" into a new, separate buffer is the closest match, but wanted to be sure.

Restating the question a bit as I'm getting some answer a bit far afield.

I have implemented device level malloc/new/realloc/etc. functions on my embedded device and wanted to double check to be sure there was no C++ realloc type function that I was unaware of.

Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
Michael Dorgan
  • 12,453
  • 3
  • 31
  • 61
  • 8
    I once asked [a similar question](http://stackoverflow.com/q/8003233/596781). – Kerrek SB Jun 24 '13 at 21:23
  • 2
    Any particular reason not to use containers that expand, like for example `std::vector`? Memory concerns? – Joachim Isaksson Jun 24 '13 at 21:23
  • Yes - you can still use realloc or any other C call. – Son-Huy Pham Jun 24 '13 at 21:24
  • @Joachimisaksson, Those C++ containers you mention will be calling my memory allocation functions. I just wanted to be sure I hadn't missed another standard resize/realloc method that was related to C++. – Michael Dorgan Jun 24 '13 at 21:27
  • 1
    @Huytard I think he's asking not whether he could use realloc, but a more C++ way to handle the kinds of situations realloc is meant for. He could also use malloc and lay out his objects as a struct himself, but he'd rather not ;) – David Souther Jun 24 '13 at 21:27
  • @KerrekSB, thanks for the link and read! That is the kind of thing I wanted to be aware of - if it had been implemented... – Michael Dorgan Jun 24 '13 at 21:31
  • 2
    @MichaelDorgan: Yeah... basically, the upshot is that there isn't really a need for this in C++. `vector` already as amortized constant pushback cost, so there isn't really any asymptotic problem to start with. – Kerrek SB Jun 24 '13 at 21:34
  • 1
    I was going to provide this [`renew`](http://ideone.com/EVkXKw) code in an answer but I don't find it a suitable solution so I threw it up on ideone just in case you find it interesting. – Captain Obvlious Jun 24 '13 at 21:34
  • Thanks @CaptainObvlious. Appreciate the code for sure. From the comments, it appears I am fine. – Michael Dorgan Jun 24 '13 at 21:37
  • @KerrekSB, make your comment an answer and I will accept it. Thanks! – Michael Dorgan Jun 24 '13 at 21:37
  • @Huytard, no, in general you cannot use realloc unless you can be certain that allocation is done using the C allocation methods (i.e. override the new/delete operators, or check your compiler documents to confirm that it uses such). Not doing so could cause underlying hard to find bugs, since using these functions are not guaranteed. – Adrian Jun 24 '13 at 21:44
  • @KerrekSB, please put your comment as an answer so that this question can be marked as answered. – Adrian Jun 24 '13 at 22:15
  • @CaptainObvlious: That is quite far from a realloc... it allocates a single object (not an array) and then reconstructs an object there. There are is no reallocation of memory or even an array of objects... – David Rodríguez - dribeas Jun 24 '13 at 22:49
  • Note that when it was first discussed, the argument fell in favor of not providing it. It would add quite a bit of complexity for limited gain (how often can you `realloc` without copying?) Then again, there are some that still want to provide that functionality in the standard. – David Rodríguez - dribeas Jun 24 '13 at 22:50
  • 1
    Hm, I don't want to create unnecessary repetition... another point worth making is that modern allocators like to pool allocations into arenas of certain sizes, and a growing `realloc` messes that up. So it might be that one day `realloc` will *always* allocate new memory and copy, in which case the there'd be nothing left to argue about. – Kerrek SB Jun 24 '13 at 22:51
  • @DavidRodríguez-dribeas correct. I had considered expanding it but the context of the OP's question changed with comments and an edit so I didn't bother to expand it. – Captain Obvlious Jun 24 '13 at 22:57
  • 2
    @KerrekSB On the other hand, modern allocators are capable of distinguishing small from large objects and handling them differently. On Unix-like platforms large objects can be (and on Linux are) allocated with `mmap`, and reallocated with `mremap`, in which case there can be a realloc that *never* copies (large enough chunks). – user4815162342 Jun 24 '13 at 22:58
  • possible duplicate of [realloc function that would work for memory allocated using new instead of realloc](http://stackoverflow.com/questions/1179669/realloc-function-that-would-work-for-memory-allocated-using-new-instead-of-reall) – Adrian McCarthy Jun 24 '13 at 23:47
  • @user4815162342: `mremap` does not guarantee that the memory region won't be moved (bitwise copied), and that could be a problem depending on what objects were allocated in the container. – David Rodríguez - dribeas Jun 25 '13 at 00:01
  • @DavidRodríguez-dribeas `mremap` will only do bitwise copy if you request it with `MREMAP_MAYMOVE`, otherwise it will either grow the allocated region in-place or fail with `ENOMEM`. If C++ supported resize on the `std::allocator` level, a clever implementation of `std::vector` could make use of it to first try to grow the container in place, and only move it if that fails. – user4815162342 Jun 25 '13 at 00:36
  • @user4815162342: For that you would need an implementation of `std::vector` that is tailored for that specific allocator. I am not saying that it cannot be done, I am only saying that it was discussed in the past and it was considered that the extra complexity was not worth the potential gain (i.e. if 90% of the time you end up moving --random number-- then there is no point). I am not an expert on allocators this is just something I read in the past. Then again, every so often there is a new push to get a remap allocator into the standard... – David Rodríguez - dribeas Jun 25 '13 at 02:45
  • @DavidRodríguez-dribeas Since the `std::allocator` interface doesn't support the concept of reallocation, it is obviously not useful to build it into `std::vector`. I was making a point that, with a sufficiently smart implementation of realloc, the concept is not as incompatible with C++ as it first seems. I suspect that such implementations of `realloc` didn't exist at the time of C++97 and by the time of C++11 it was too late due to backward compatibility constraints. – user4815162342 Jun 25 '13 at 07:44
  • @user4815162342: The point is that you need to start providing different implementations of the containers that can make use of the additional features. It is far from impossible, our implementation of the standard libraries manages bitwise movable types specially doing most of what would be needed for a realloc-ish allocator (although determined purely on the stored type). The point is still the same: you would need to reimplement all containers for this allocator, you could not combine polymorphic allocators (we use them extensively) so that *sometimes* you avoid the copy when growing. – David Rodríguez - dribeas Jun 25 '13 at 13:04
  • @DavidRodríguez-dribeas The containers would need to be changed, but the change is not necessarily pervasive, nor would the implementations really be all that different. For example, given a `try_inplace_realloc` primitive (implemented on Linux by a call to `mremap` without allowing bitwise copy), a vector could first try the in-place resize and then, only if it fails, fall back to copy-and-destroy (move in C++11). – user4815162342 Jun 25 '13 at 14:09
  • Be the changes easy or hard, it is also important who the "you" who implements them is. If the in-place reallocation possibility were part of the standard, the (popular implementations of) STL containers would soon start using it because it would gain them efficiency. The amount of efficiency gained can be disputed and is probably the reason why this didn't make it to the standard. But some people refuse to even acknowledge that in-place reallocation is a legitimate need in C++, citing bitwise move done by a typical `realloc` (or, as here, pooled allocations). This what I'm arguing against. – user4815162342 Jun 25 '13 at 14:10
  • @user4815162342: As I already mentioned, it would make things very complex on the implementor of the standard library, and you can get most of the way there without a realloc implementation by detecting (tagging) bitwise movable and using `memcpy` to *move* data when the container grows. Unless your data size is HUGE and realloc would just extend it (i.e. no move) that will be just as efficient and can use most of the same code base than the rest of the types (i.e. no specialization on the allocator type, which is *important* if you want to use polymorphic allocators) – David Rodríguez - dribeas Jun 25 '13 at 14:20
  • @DavidRodríguez-dribeas The complexity you mentioned referred to deciding reallocation strategy on the property of the stored type, which I imagine is hairy. What I'm referring to is something much simpler: a code path in which the element-by-element move is not necessary because the container has grown with all elements having remained in place: `if (!try_in_place_realloc(...)) { current code that moves each element to newly allocated storage }`. – user4815162342 Jun 25 '13 at 14:27
  • @user4815162342: The problem is that you need to specialize the container for that allocator, which means that all of the hair that is already there to efficiently handle other things (nothrow vs. throw move/copy constructors...) would have to be duplicated to handle the unstandard allocator. The complexity is not the allocation in itself, is having to manage `std::vector<>` for today's conforming allocators and `std::vector<>` for a realloc allocator. The alternative would be forcing `try_in_place_realloc` on the allocator interface, which is not backwards compatible with user allocators – David Rodríguez - dribeas Jun 25 '13 at 14:44
  • ... it would enable a single implementation of the containers, but existing user provided allocators could not be used in the new variants of the containers, unless you modify the containers again to detect old/new style allocators in which case you are back in case 1, where you need to specialize containers to manage this... – David Rodríguez - dribeas Jun 25 '13 at 14:46
  • @DavidRodríguez-dribeas I see what you mean. Still, since STL types are templated by allocator type, I would expect their specialization to be fairly straightforward with the use of template trickery not unlike one already used in their implementation. But this is just a hunch - as I am far from an expert on the matter, I will not argue it further. – user4815162342 Jun 25 '13 at 15:00
  • @user4815162342: The problem is that those are orthogonal types. Specialization of classes requires *copying* all of the code that is shraed, although that can be improved through inheritance. Because this modification is orthogonal to the existing ones, it would require doubling (at least conceptually) the number of actual implementations. In practice there are less, although at the same time more complex types in usual implementations. – David Rodríguez - dribeas Jun 25 '13 at 15:19

1 Answers1

4

No, there is no direct equivalent. You would have to do the implementation yourself. Since a class really shouldn't change its size, this isn't really an issue. Move semantics can handle most of these cases.

However, there are some classes that use header info + tail end allocated data. To code these 'properly' you would have to override the operator new() and operator delete() function for the class to handle this additional 'flexible' data. How you 'reallocate' the data is specific to your needs.

If this doesn't answer your question, post an example of what you are attempting.

Adrian
  • 10,246
  • 4
  • 44
  • 110
  • Nice answer, but I believe @KerrekSB above gave me the info I needed. I am, or have already in this case, coded all the low level memory allocation glue code to fit with the standard allocators and I just wanted to be sure there was no C++ realloc equivalent that I was missing. +1 and thanks. – Michael Dorgan Jun 24 '13 at 21:43
  • I give you the prize as everyone else has gotten into a C++11 argument :) – Michael Dorgan Jun 25 '13 at 17:32