1

Consider this example,

// x is a int* allocated previously via 'new'
delete x;
x = new int;

Does this code always guarantee a memory allocation in last line as there is definitely memory left to hold an int at least from the previous deallocation.

In case the standard currently does not provide any such guarantee, is that decision because of a room for a potential optimization?

Does any popular implementations get advantage of that optimization or do all of them simply guarantees the allocation after deallocation?

Or is it just impossible to provide such guarantee? In that case, can you provide a case where the allocation after the deallocation is absolutely bound to fail.

When I say allocation after deallocation in the above question, I'm talking about allocation of equal or smaller size than deallocation as I know allocating a larger size may not always be possible due to insufficient memory.

Sourav Kannantha B
  • 2,860
  • 1
  • 11
  • 35
  • 1
    Dupe https://stackoverflow.com/a/6624123/4165552 ? – pptaszni Jul 24 '23 at 06:52
  • 3
    Of course not, you can overload operator `new` which will toss a coin each time on whether it will fail straight away or try to process your request. – Quimby Jul 24 '23 at 07:01
  • 3
    "there is definitely memory left to hold an int" what makes you think so? First of all: you don't even know what allocator you use, since these can be switched dynamically. Moreover: do you think your process is the only thing that runs on your machine? There is absolutely no way to guarantee such thing, unless you use custom, hand written allocator, fully controlled by you. – freakish Jul 24 '23 at 07:27
  • 3
    Memory is a shared resource. How can anyone guarantee that, between the calls to `delete` and `new`, some other process did not allocate memory, causing the available memory to get depleted? OK, a single `int` is really an extremely small amount to allocate, and such an occasion would be very improbable to happen. But if you're talking about the general case, for example, a multi-megabyte vector, it'll be easier to understand why no such guarantee could possibly be provided. – heap underrun Jul 24 '23 at 07:45
  • @freakish I'm not switching allocators between `delete` and `new`. The memory released by `delete` must either be with the allocator itself or the allocator must have returned it to the OS. In the former case, the allocator can immediately return back the memory. In the latter case, I thought whole 2^64 bytes in the virtual address space is reserved for a process. But, from your comments, I think I'm wrong in that. – Sourav Kannantha B Jul 24 '23 at 09:21
  • @heapunderrun I forgot that memory is shared between processes. Now I get it. But if memory is not released to OS yet, then it is possible to guarantee right? – Sourav Kannantha B Jul 24 '23 at 09:23
  • 1
    @SouravKannanthaB that's not what I mean by "dynamic switch". I mean that you can run your compiled binary with different allocators simply by using LD_PRELOAD env variable. At least under Linux. And therefore you can run the code with literally any allocator without recompilation. And what allocators do is an implementation detail of the allocator itself, you have no control over that. And no standard exists to mandate such behavior. – freakish Jul 24 '23 at 10:03
  • 1
    @SouravKannanthaB you have no control over what and when is released to OS. And even if the allocator doesn't release memory to OS it still may fail to allocate memory for whatever reason. It is an implementation detail of allocator, which you have no control over. Unless you use a custom, hand written allocator, as I already said before. Which is hard to do correctly and efficiently, and unlikely to bring any benefit. Just accept the reality. – freakish Jul 24 '23 at 10:10
  • @freakish Thanks. No way I'm writing a custom allocator now. Normally when C++ standard leaves something as undefined or implementation defined, it is generally done to exploit / take advantage of some platform specific behavior. So I was curious to know what benefit can there be in this case. Now I understand it is simply not possible to provide such guarantee. – Sourav Kannantha B Jul 24 '23 at 10:25
  • 1
    @SouravKannanthaB note however that people do write their own allocators. For example high level language runtimes (C#, Java) or database servers will have custom allocators. Often based on low level allocators (e.g. they allocate big chunk through malloc, and then do manual allocation from that chunk). Because they need strict control over memory. So it is not an insane idea. Still difficult, and I advice against it, unless absolutely necessary. – freakish Jul 24 '23 at 10:29

1 Answers1

4

There is no guarantee that you'll get a new memory location, in fact the standard doesn't provide any details about how memory allocations work, new returns a pointer to a new object, that's about all the standard says. In some implementations you might even find that your code always produces the same object and there's nothing illegal about that according to the standard.

https://en.cppreference.com/w/cpp/language/new

In places where the behaviour of the language isn't important to the user the standard is deliberately unspecified in order to not restrict implementers. For example in the case of new the memory allocation could be implemented using a heap, using a fixed size pool of pre-allocated memory or it could even have a separate pool of memory blocks for each object size.

Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
  • Suppose new is implemented just as a syscall using `sbrk` or `mmap/munmap`. Then, does that implementation can guarantee allocation after a deallocation? – Sourav Kannantha B Jul 24 '23 at 07:09
  • 1
    @SouravKannanthaB No – Ted Lyngmo Jul 24 '23 at 07:19
  • 1
    @SouravKannanthaB memory allocators do a lot more than just some syscalls. In fact they tend to minimize the number of syscalls. I'm talking about malloc. Moreover we can dynamically switch malloc implementation at runtime, e.g. from libc to jemalloc. There is absolutely no way to guarantee what you want. – freakish Jul 24 '23 at 07:25
  • 1
    The question is not whether the returned location is "new" (i.e., different from earlier allocations), but whether the allocation is successful in the first place. – j6t Jul 24 '23 at 07:33