Hacker News new | ask | show | jobs
by swiftcoder 247 days ago
> even the cpp one, will reserve atleast the number of elements given

The C++ one, however, will not reserve more than you ask for (in the case that you reserve greater than the current capacity). It's an exact reservation in the rust sense.

> reserve() will grow the underlaying memory area to the next increment, or more than one increment, while reserve_exact() will only grow the underlaying memory area to the next increment, but no more than that

No, not quite. Reserve will request as many increments as it needs, and reserve_exact will request the exact total capacity it needs.

Where the docs get confusing, is that the allocator also has a say here. In either case, if you ask for 21 items, and the allocator decides it prefers to give you a full page of memory that can contain, say, 32 items... then the Vec will use all the capacity returned by the allocator.

3 comments

As far as I can tell, in the current implementation, reserve_exact is indeed exact. The only situation in which the capacity after calling reserve_exact will not equal length + additional is when it was already greater than that. Even if the allocator gives more than the requested amount of memory, the excess is ignored for the purposes of Vec's capacity: https://github.com/rust-lang/rust/blob/4b57d8154a6a74d2514cd...

Of course, this can change in the future; in particular, the entire allocator API is still unstable and likely won't stabilize any time soon.

Maybe more interestingly, line 659, slightly above that, explains that we know we got [u8] but today the ordinary Rust allocator promises capacity is correct, so we just ignore the length of that slice.

We could, as that comment suggests, check the slice and see if there's enough room for more than our chosen capacity. We could also debug_assert that it's not less room, 'cos the Allocator promised it would be big enough. I dunno if that's worthwhile.

https://en.cppreference.com/w/cpp/container/vector/reserve.h...

says

> Increase the capacity of the vector (the total number of elements that the vector can hold without requiring reallocation) to a value that's greater or equal to new_cap.

I belive that the behaviour of reserve() is implementation defined.

Because there's only a single function here, it has to either be Vec::reserve or Vec::reserve_exact

If you don't offer Vec::reserve_exact then people who needed that run out of RAM and will dub your stdlib garbage. If you don't offer Vec::reserve as we've seen C++ programmers will say "Skill issue" whenever a noob gets awful performance as a result. So, it's an easy choice.

That said MSVC,GCC and clang all implement it to allocate an exact value.
> In either case, if you ask for 21 items, and the allocator decides it prefers to give you a full page of memory that can contain, say, 32 items... then the Vec will use all the capacity returned by the allocator.

It would be nice if this were true but AFAIK the memory allocator interface is busted - Rust inherits the malloc-style from C/C++ which doesn’t permit the allocator to tell the application “you asked for 128 bytes but I gave you an allocation for 256”. The alloc method just returns a naked u8 pointer.

The global allocator GlobalAlloc::alloc method does indeed return a naked pointer

But the (not yet stable) Allocator::allocate returns Result<NonNull<[u8]>, AllocError> --- that is, either a slice of bytes OR a failure.

Vec actually relies on Allocator not GlobalAlloc (it's part of the standard library so it's allowed to use unstable features)

So that interface is allowed to say you asked for 128 bytes but here's 256. Or, more likely, you asked for 940 bytes, but here's 1024. So if you were trying to make a Vec<TwentyByteThing> and Vec::with_capacity(47) it would be practical to adjust this so that when the allocator has 1024 bytes available but not 940 we get back a Vec with capacity 51 not 47.