2

In C, we can simply use realloc() to increase/decrease the size of memory a pointer is pointing to.

Is there an equivalent reallocation operator/function in C++ in the context of having used "new" to initially allocate the memory?

Gary Allen
  • 1,218
  • 1
  • 13
  • 28
  • 1
    You mean for dynamic arrays? The easiest way would probably be to use [`std::vector`](https://en.cppreference.com/w/cpp/container/vector) instead of raw pointers. If this is applicable and allowed in your case. – Lukas-T Aug 13 '20 at 06:53
  • 2
    Looks a bit like https://stackoverflow.com/questions/3482941/how-do-you-realloc-in-c – Carlos Aug 13 '20 at 06:53
  • 1
    You can of course use realloc in C++ if it fits your needs. – john Aug 13 '20 at 06:55
  • @churill No offence, but that is such a typical answer on the C++ side of this forum. My use case is clearly different, using or not using "new" is not part of the discussion, and I simply want to know if reallocation is possible. Don't mean to be rude, but you get these kind of replies a lot on this forum and it bugs me a bit lol – Gary Allen Aug 13 '20 at 06:56
  • 1
    You get these kinds of replies because that's the way C++ is supposed to be used, with `new` and with all the libraries that simplify its usage :) Maybe explaining what forces you to not use `new` (but allows you to use `malloc` & co.) would help gets you more useful answers. – bracco23 Aug 13 '20 at 06:59
  • @GaryAllen That's allright :) Just mentioned it, because way to often people on SO try to do crazy things with raw pointers, because they don't seem to know about STL-containers. In this respect, no, there is no such a thing like `realloc` in C++. – Lukas-T Aug 13 '20 at 07:00
  • 1
    @bracco23 no, you shouldn't have to explain every single detail when asking such a simply question, I'm sorry. That's the beauty of forums - you can often (not always, of course) but often isolate a single part of your program which needs fixing/help and ask about it online. Having to explain exactly what I'm doing every single time I ask a question when it isn't necessary is a pain in the ass – Gary Allen Aug 13 '20 at 07:01
  • @GaryAllen how memory is allocated in case of `new` can be controlled by the developer using the `operator new` one a global scope, and for each type individually. There is no `new` compatible `realloc` in the stdlib that takes this into account, only containers like `std::vector` would provide this functionality. – t.niese Aug 13 '20 at 07:02
  • @GaryAllen Isolating a [mre] is the point to ask simple, answerable questions, but you should not leave out details that would change the best solution. There is no need to do a lengthy explanation of you actual project, but if, as an example, you're working on an embedded system and you cannot use dynamic memory at all, that is something that should be mentioned. Even if it may have nothing to do with your problem at all. – bracco23 Aug 13 '20 at 07:06
  • @GaryAllen You can have the best of both worlds (arguably). Use malloc/realloc/free to allocate memory and placement new and explicit destructor calls to create and destroy objects. – john Aug 13 '20 at 07:12
  • 2
    @bracco23 "minimal reproducible example" applies when there is some behaviour to reproduce, i.e. a program that does not do what is desired. If I ask "how to draw a squiggle" because I have no idea how to draw stuff, then presenting a program that prints "hello world" is pretty useless. – n. m. could be an AI Aug 13 '20 at 07:42
  • 2
    @bracco23: While many things can be *viewed* as an `XY` problem (https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem), sometimes you really *do* just want to know how to `Y` :-) – paxdiablo Aug 13 '20 at 09:03

1 Answers1

3

No, there is no renew call :-)

And, to be honest, with all the rich (and auto-sizing) data structures provided by C++, there's little need for it. For example, while C strings might need to be resized to add more text, std::string just takes care of it for you. As does std::vector for other arrays, and so on.

If you really wanted to go against the last twenty years of improvement in C++ and do that, you can always revert to the C way (since malloc, free and realloc are available), but I'd suggest not doing that if you can avoid it.

You could also try to implement a renew feature but it's going to be slightly harder as you won't have access to internal memory allocation data (as realloc does). That means every renew is probably going to be an "allocate and copy" operation.

And, if you provide a class that can give you that information, you're already into the "slightly more complex than a byte array" arena, so would probably just step up to letting the class itself do the heavy lifting of reallocation.


As an aside, I've never really been that fond of realloc since, if it fails, you've generally lost the old pointer in a memory leak. That means I've always had to do things like:

int betterReAlloc(void **pOldPtr, size_t newSz) {
    void *newptr = realloc(*pOldPtr, newSz);
    if (newPtr != NULL) *pOldPtr = newPtr)
    return newptr != NULL;
}

char *ptr = somethingValidlyMalloced();
if (! betterReAlloc(&ptr, BETTER_SIZE)) {
    puts("Cannot realloc, using original");
}
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 1
    Hmmm, seems like its a missing language feature imo. What if I'm writing custom data structures? What if I'm writing low level code which requires "new" but can't afford the overhead of a complex data structure? etc. But oh well. I guess it is what it is – Gary Allen Aug 13 '20 at 06:58
  • 2
    @Gary, if it's low-level enough, you can still *use* `malloc/free/realloc`. However, hardly anyone I know even uses naked `new` anymore - we've all mostly moved on to smart pointers. It's even one of the things in our coding guidelines that you'll have to justify in code reviews :-) – paxdiablo Aug 13 '20 at 07:00
  • I'll accept your answer because you gave me the answer, thanks, but there are several use cases where new is definitely still applicable (hybrid C/C++ code, legacy code, relatively low-level code, libraries such as Qt/wxWidgets, etc. etc. etc.) – Gary Allen Aug 13 '20 at 07:04
  • 1
    @GaryAllen `[...]What if I'm writing low level code which requires "new" but can't afford the overhead of a complex data structure[...]` in which case wouldn't `std::vector` work there? You could always use e.g. `std::vector` when you would have used `new char[]` otherwise. – t.niese Aug 13 '20 at 07:06
  • don't need to revert to `realloc` days.. `realloc` literally was implemented as `malloc` and `memcpy`, with `free`-ing old chunk of memory. Common mistake of C beginners (and novice C++ coders who try to use that function) is use old pointer after calling `realloc`. ALL data was copied to new location. If required such behavior can be emulated with `std::copy` – Swift - Friday Pie Aug 13 '20 at 07:11
  • @Swift-FridayPie That's strictly implementation dependent. Of course, there are implementations that do it the way you described. But there are other implementations that will avoid the reallocation in many cases. For instance, if your `malloc()` really only thinks in block sizes that are powers of two, the matching `realloc()` could easily check whether the new size is still within the limits of the block, and do exactly nothing when that's the case. – cmaster - reinstate monica Aug 13 '20 at 07:17
  • 1
    @Swift, that is *not* necessarily the case. Reallocation is free to return exactly the same address (without modifying any memory arenas) if reducing (or even if increasing, provided there's room after the block). From the standard: `The realloc function returns a pointer to the new object (which may have the same value as a pointer to the old object)`. – paxdiablo Aug 13 '20 at 07:18
  • @cmaster-reinstatemonica you mean if it can expand it to page limits or even to next page beyond its end. Or before beginning, but it still have to call a low-level equivalent of `malloc`. That's more typical for real-time-esque platforms, safe embedded platforms and modern multi-threaded won't allow this because of possible race conditions or such behavior maybe hidden in "malloc". E.g. implementation in libstdc++: https://code.woboq.org/userspace/glibc/malloc/malloc.c.html#3136 – Swift - Friday Pie Aug 13 '20 at 07:24
  • 2
    There *is* a clause that states it "deallocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by size" but, as with all things in the standard, that's not necessarily so, because of the "as-if" rule. Implementations can do whatever they want provided the observable behaviour matches the standard. – paxdiablo Aug 13 '20 at 07:25
  • @paxdiablo it may stay same if size had been same, that only time which it does nothing. Also it may just call `free` if new size is 0. Also I don't remember if as-if rule was applied to C. – Swift - Friday Pie Aug 13 '20 at 07:27
  • @Swift, it's in the program execution section of the standard, if you're interested. I would of course suggest a strong drink before venturing into the C standard, indeed *several* strong drinks for the later C++ ones :-) – paxdiablo Aug 13 '20 at 07:31
  • @paxdiablo eh, only because it's no longer K&R C, which I knew and wrote in. Now what kind of brain-altering substance I would need to code in Fortran-77 again? – Swift - Friday Pie Aug 13 '20 at 07:35
  • @Swift-FridayPie have you ever tried it yourself? https://ideone.com/KVlbJ6 – n. m. could be an AI Aug 13 '20 at 07:36
  • @Swift-FridayPie For Fortran-77 mere drinks won't suffice. And I guess, any drug strong enough for that would inevitably produce a horror trip... – cmaster - reinstate monica Aug 13 '20 at 07:57
  • @Swift-FridayPie Back to `realloc()`: When I implemented an `operator new()`, it would classify all small objects into a small number of classes like 32 bytes, 64 bytes, 128 bytes, etc. When asked for a 77 byte block, it would return the address of a 128 byte one. Now, that was an `operator new()` so I didn't worry about `realloc()`, but the equivalent would work for a `malloc()` implementation as well. So, if a `realloc()` resizes the 77 byte block to a 123 byte block, my realloc would simply compute the new block size to be 128 bytes, and do a fast return. – cmaster - reinstate monica Aug 13 '20 at 08:02
  • 1
    I remember doing something similar on an embedded system. We had a pool of 128-byte blocks and 1K blocks. If you allocated under 129, you got a 128-byter and could realloc to your hearts content as long as you stayed below 129. Ditto for the 1K blocks. If you realloced a 128-byter to be 129b-1K, it got copied to a new 1Ker and the 128-byter was freed. Going the other way, we rarely moved 1Kers back to a 128-byter unless 1Kers were running low. If *anything* asked for more than 1K, it was rejected immediately (we'd figured out the largest block needed was slightly under a K). – paxdiablo Aug 13 '20 at 08:07
  • It was blindingly fast as well (for a slow embedded system) since it didn't have to worry about buddy algorithms, or splitting and recombining blocks. – paxdiablo Aug 13 '20 at 08:18
  • @paxdiablo I know, seen and used something liek that too. That seem to be a general strategy for pools. Also some implementations of ISO library are doing same but that's _above_ the runtime library level. Small embedded systems and micro-controller bootstraps are very different story from multipurpose OS, embedded systems I mentioned are things like smart-phones and such where they run multiple threads and processes on top of separate kernel and application isn't really in direct control of heap – Swift - Friday Pie Aug 13 '20 at 09:46
  • @Swift-FridayPie What do you mean by "application isn't really in direct control of heap"? That's only true for VM code like Java Byte Code. A compiled executable that is able to call into the kernel directly (C/C++) is in full control of its heap. And we are talking about `malloc()`, `realloc()` and `new` here which are C/C++ functions. Any program that uses these functions directly can also provide its own implementations that rely directly on `mmap()`. Whether such an implementation wants to support multithreading is up to the needs of the application. – cmaster - reinstate monica Aug 13 '20 at 13:58