# Guarantee that Vec::default() does not allocate?

**URL:** <https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903>\
**Category:** help\
**Created:** [August 15, 2022, 12:10pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903 "2022-08-15T12:10:07Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![jbe](https://avatars.discourse-cdn.com/v4/letter/j/f6c823/32.png) [@jbe](https://users.rust-lang.org/u/jbe)\
**Post date:** [August 15, 2022, 12:10pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/1 "2022-08-15T12:10:07Z")

</div>

Documentation of `impl<T> Default for Vec<T>` reads like this:

> Creates an empty `Vec<T>`.

Being empty means the `Vec`'s [length is zero](https://github.com/rust-lang/rust/blob/1.63.0/library/alloc/src/vec/mod.rs#L1946-L1960), but it doesn't say anything about its capacity, right?

With the current implementation, there will be no allocation, as can be seen in the [implementation](https://github.com/rust-lang/rust/blob/1.63.0/library/alloc/src/vec/mod.rs#L2923-L2930), which uses [`Vec::new`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.new). But I guess this is, strictly speaking, not guaranteed, right?

Maybe the API specification could/should be extended in that matter? I'm asking because I use [`std::mem::take`](https://doc.rust-lang.org/std/mem/fn.take.html) on a `&mut Vec<_>` and I wouldn't want an allocation to happen.

Second question: I rely on `Vec::default().capacity() == 0`. I assume this is also not guaranteed, even if it seems to be true in the [current implementation](https://github.com/rust-lang/rust/blob/1.63.0/library/alloc/src/raw_vec.rs#L119-L124)? ([Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e31724ef047c83ec0ac77946b94a9065)) Adding such a guarantee to `std` seems to be less trivial though, I guess, because future implementations might handle `Vec`s with small lengths differently (i.e. without allocating), or am I wrong?

---

<div class="post-metadata">

**Author:** ![psionic12](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/psionic12/32/22351_2.png) [@psionic12](https://users.rust-lang.org/u/psionic12)\
**Post date:** [August 15, 2022, 12:16pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/2 "2022-08-15T12:16:15Z")

</div>

I found codes like this:

```rust
    /// Like `new`, but parameterized over the choice of allocator for
    /// the returned `RawVec`.
    pub const fn new_in(alloc: A) -> Self {
        // `cap: 0` means "unallocated". zero-sized types are ignored.
        Self { ptr: Unique::dangling(), cap: 0, alloc }
    }

```

`new_in` is called by `new`, so I think 0 capacity is guaranteed.

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/steffahn/32/47569_2.png) [@steffahn](https://users.rust-lang.org/u/steffahn)\
**Post date:** [August 15, 2022, 12:16pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/3 "2022-08-15T12:16:18Z")

</div>

If you're _only_ interested in this guarantee for performance reasons (i. e. your use-case wouldn't _misbehave_ if there was any allocation involved), I believe it's fine to rely on it without further explicit guarantees because a change here would be considered a performance regression in the standard library.

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/steffahn/32/47569_2.png) [@steffahn](https://users.rust-lang.org/u/steffahn)\
**Post date:** [August 15, 2022, 12:21pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/4 "2022-08-15T12:21:15Z")

</div>

`Vec::new` being `const fn` might already constitute a guarantee that there's no run-time allocation involved... well, at least if you assign it to a `const` value first (since compile-time dynamic allocations might eventually be a thing).

---

<div class="post-metadata">

**Author:** ![jbe](https://avatars.discourse-cdn.com/v4/letter/j/f6c823/32.png) [@jbe](https://users.rust-lang.org/u/jbe)\
**Post date:** [August 15, 2022, 12:22pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/5 "2022-08-15T12:22:32Z")

</div>

> [@psionic12](#):
>
> I found codes like this: […]

Yeah, the current implementation always has a capacity of zero. But I wonder if it's guranteed that this stays the same in future versions of `std`.

> [@steffahn](#):
>
> If you're _only_ interested in this guarantee for performance reasons (i. e. your use-case wouldn't _misbehave_ if there was any allocation involved), […]

I think in my case, I would create a memory leak. This is my use-case:

```rust
#[derive(Debug)]
pub struct BufWriteGuard<T> {
    buffer: Vec<T>,
    recycler: Option<mpsc::UnboundedSender<Vec<T>>>,
}

impl<T> BufWriteGuard<T> {
    fn new(buffer: Vec<T>, recycler: mpsc::UnboundedSender<Vec<T>>) -> Self {
        BufWriteGuard {
            buffer,
            recycler: Some(recycler),
        }
    }
    pub fn finalize(mut self) -> BufReadGuard<T> {
        BufReadGuard::new(take(&mut self.buffer), self.recycler.take().unwrap())
    }
}

impl<T> Drop for BufWriteGuard<T> {
    fn drop(&mut self) {
        if self.buffer.capacity() > 0 {
            let _ = self.recycler.as_ref().unwrap().send(take(&mut self.buffer));
        }
    }
}

```

I rely on the drop handler to not "recycle" a default `Vec`.

_Edit:_ The memory leak occurs because I will "recycle" the `Vec` and another default `Vec`, which makes the `mpsc` grow indefinitely here:

```rust
pub struct BufPool<T> {
    recycler: mpsc::UnboundedSender<Vec<T>>,
    dispenser: mpsc::UnboundedReceiver<Vec<T>>,
}

impl<T> BufPool<T> {
    pub fn new() -> Self {
        let (recycler, dispenser) = mpsc::unbounded_channel::<Vec<T>>();
        Self {
            recycler,
            dispenser,
        }
    }
    pub fn get(&mut self) -> BufWriteGuard<T> {
        let buffer = match self.dispenser.try_recv() {
            Ok(mut buffer) => {
                buffer.clear();
                buffer
            }
            Err(_) => {
                println!("Create new buffer");
                Vec::new()
            }
        };
        BufWriteGuard::new(buffer, self.recycler.clone())
    }
}

```

* * *

> [@steffahn](#):
>
> […] I believe it's fine to rely on it without further explicit guarantees because a change here would be considered a performance regression in the standard library.

I'm not sure if I can follow your reasoning. Does the standard library guarantee no future changes will cause any program to run slower, independently on how the standard library is used?

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/steffahn/32/47569_2.png) [@steffahn](https://users.rust-lang.org/u/steffahn)\
**Post date:** [August 15, 2022, 12:24pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/6 "2022-08-15T12:24:40Z")

</div>

> [@jbe](#):
>
> I think in my case, I would create a memory leak.

I don't immediate see where exactly the leak would happen, perhaps you can point to it in the code example?

---

<div class="post-metadata">

**Author:** ![jbe](https://avatars.discourse-cdn.com/v4/letter/j/f6c823/32.png) [@jbe](https://users.rust-lang.org/u/jbe)\
**Post date:** [August 15, 2022, 12:25pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/7 "2022-08-15T12:25:22Z")

</div>

I extended my code sample above.

* * *

Also see [full Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=312d90261e8e419ac62fe42bc637a5ee).

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/steffahn/32/47569_2.png) [@steffahn](https://users.rust-lang.org/u/steffahn)\
**Post date:** [August 15, 2022, 12:28pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/8 "2022-08-15T12:28:12Z")

</div>

> [@jbe](#):
>
> Does the standard library guarantee no future changes will cause any program to run slower, independently on how the standard library is used?

Changes in performance are a trade-off; relying (for performance) on empty Vec freation) creation to be cheap and allocation-free is super common, I would assume, and also I can't imagine any _benefit_ in changing this, so such a change will never happen as it's a terrible trade-off.

There's no guarantee as strong as you asked for ("independently of how the standard library is used"), but as this is a common and natural use-case, not anything weird or so, it should be covered by the general principle that the standard library should contain good and performant code.

---

<div class="post-metadata">

**Author:** ![jbe](https://avatars.discourse-cdn.com/v4/letter/j/f6c823/32.png) [@jbe](https://users.rust-lang.org/u/jbe)\
**Post date:** [August 15, 2022, 12:29pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/9 "2022-08-15T12:29:09Z")

</div>

Would it make sense to add these (sane) assumptions to `std`'s API specification?

I understand I can likely rely on it, but usually feel safer if I don't make assumptions that aren't explicitly guranteed… (if this could result in memory leaks, for example).

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/steffahn/32/47569_2.png) [@steffahn](https://users.rust-lang.org/u/steffahn)\
**Post date:** [August 15, 2022, 12:34pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/10 "2022-08-15T12:34:14Z")

</div>

I do support the idea of documenting properly that `Vec::new` or `Vec::default` won't allocate. I'm just trying to justify why it's even a reasonably thing to assume (for performance reasons) _right now_ without the explicit guarantee. Even with a guarantee that no allocation is involved, you technically wouldn't have a guarantee that e. g. `mem::forget`ting a `Vec::new` or `Vec::default` wouldn't leak anything else. That's entirely hypothetical, but creating a Vec might as well modify some other global state that's supposed to be cleaned up when dropped. (Except it probably can't because it's a `const fn`, but my point was about "this doesn't allocate" possibly _also_ still being vague/imprecise on certain points or use-cases.)

---

<div class="post-metadata">

**Author:** ![jbe](https://avatars.discourse-cdn.com/v4/letter/j/f6c823/32.png) [@jbe](https://users.rust-lang.org/u/jbe)\
**Post date:** [August 15, 2022, 12:36pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/11 "2022-08-15T12:36:44Z")

</div>

Hmmm… 🤔 Now that I think about it, it's less the "allocation" that bothers me, but more that I rely on the capacity being zero. Perhaps the "clean" way would be to use an `Option<Vec>` instead of a `Vec` in my use case, but I refrained from doing that due to the overhead of unwrapping (in safe Rust).

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/steffahn/32/47569_2.png) [@steffahn](https://users.rust-lang.org/u/steffahn)\
**Post date:** [August 15, 2022, 12:36pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/12 "2022-08-15T12:36:58Z")

</div>

Even in this full playground, I still don't see where you assume a leak could happen if empty vecs did allocate. Would you mind explaining this better?

* * *

Oh.. with your latest comment in mind, are the capacity checks relevant?

If that's a problem, you _do_ have a problem because if `T` is a zero sized type, IIRC, a `Vec::default` will have capacity `usize::MAX` or something like that.

_Edit:_ [Yup, I _did_ recall correctly.](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=07f984df83b3251e4ba13c6d034f11ad)

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/steffahn/32/47569_2.png) [@steffahn](https://users.rust-lang.org/u/steffahn)\
**Post date:** [August 15, 2022, 12:44pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/13 "2022-08-15T12:44:55Z")

</div>

Presumably, for zero-sized types, you want to skip any recycling logic altogether, anyway 😅

---

<div class="post-metadata">

**Author:** ![jbe](https://avatars.discourse-cdn.com/v4/letter/j/f6c823/32.png) [@jbe](https://users.rust-lang.org/u/jbe)\
**Post date:** [August 15, 2022, 12:51pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/14 "2022-08-15T12:51:28Z")

</div>

> [@steffahn](#):
>
> If that's a problem, you _do_ have a problem because if `T` is a zero sized type, IIRC, a `Vec::default` will have capacity `usize::MAX` or something like that.
> 
> _Edit:_ [Yup, I _did_ recall correctly.](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=07f984df83b3251e4ba13c6d034f11ad)

😱

> [@steffahn](#):
>
> Even in this full playground, I still don't see where you assume a leak could happen if empty vecs did allocate. Would you mind explaining this better?

I slightly modified the example because there was yet a panic when `capacity` wasn't zero. This demonstrates the problem of memory leak now: [Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=1573f75f1dc71976a05907a0c6c7cfca).

> [@steffahn](#):
>
> Oh.. with your latest comment in mind, are the capacity checks relevant?

Not sure what you mean? I "misuse" the [`capacity`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.capacity) method to "detect" default `Vec`s that were left by [`std::mem::take`](https://doc.rust-lang.org/std/mem/fn.take.html).

I guess I'll have to use an `Option<Vec>` to be clean and take from the `&mut Option<Vec>` instead of from the `&mut Vec`. But I don't like the `unwrap` overhead at runtime… 🙁

* * *

Nonetheless, I think `Vec::default` should give the same guarantees as `Vec::new`.

---

<div class="post-metadata">

**Author:** ![2e71828](https://avatars.discourse-cdn.com/v4/letter/2/3e96dc/32.png) [@2e71828](https://users.rust-lang.org/u/2e71828)\
**Post date:** [August 15, 2022, 12:52pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/15 "2022-08-15T12:52:37Z")

</div>

> [@jbe](#):
>
> I'm asking because I use [`std::mem::take`](https://doc.rust-lang.org/std/mem/fn.take.html) on a `&mut Vec<_>` and I wouldn't want an allocation to happen.
> 
> Second question: I rely on `Vec::default().capacity() == 0`. I assume this is also not guaranteed,

You can always `std::mem::replace(&mut v, Vec::with_capacity(0))` instead, which explicitly spells out the conditions you rely on.

---

<div class="post-metadata">

**Author:** ![jbe](https://avatars.discourse-cdn.com/v4/letter/j/f6c823/32.png) [@jbe](https://users.rust-lang.org/u/jbe)\
**Post date:** [August 15, 2022, 12:54pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/16 "2022-08-15T12:54:59Z")

</div>

Nice idea, but:

> Constructs a new, empty `Vec<T>` with at least the specified capacity.

[`with_capacity`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.with_capacity) can return a `Vec` with higher capacity, as also demonstrated by @steffahn:

```rust
fn main() {
    assert_eq!(Vec::<()>::with_capacity(0).capacity(), usize::MAX)
}

```

([Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=2b5a496b239e0eb2e38c544d60600ca0))

Even if this is an exotic ZST case, the documentation explicitly says "at least".

---

<div class="post-metadata">

**Author:** ![2e71828](https://avatars.discourse-cdn.com/v4/letter/2/3e96dc/32.png) [@2e71828](https://users.rust-lang.org/u/2e71828)\
**Post date:** [August 15, 2022, 12:57pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/17 "2022-08-15T12:57:33Z")

</div>

It also states explicitly that "If `capacity` is 0, the vector will not allocate." So, aside from ZSTs, a capacity request of 0 _will_ be honored exactly.

That said, using an `enum` to provide your sentinel value instead of an implementation detail of `Vec` seems like the best approach from a maintainability perspective.

---

<div class="post-metadata">

**Author:** ![jbe](https://avatars.discourse-cdn.com/v4/letter/j/f6c823/32.png) [@jbe](https://users.rust-lang.org/u/jbe)\
**Post date:** [August 15, 2022, 1:07pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/18 "2022-08-15T13:07:12Z")

</div>

> [@2e71828](#):
>
> It also states explicitly that "If `capacity` is 0, the vector will not allocate." So, aside from ZSTs, a capacity request of 0 _will_ be honored exactly.

But couldn't a `Vec` keep a small number of elements on the stack instead of the heap? (I know it doesn't, but a future version could hypothetically, right?) Thus it could have a capacity \> 0 even without allocating.

> [@2e71828](#):
>
> That said, using an `enum` to provide your sentinel value instead of an implementation detail of `Vec` seems like the best approach from a maintainability perspective.

Yes, I think it's best to do that. I'd use an `Option` instead of an `enum` though. Something like this: ~~[Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=1573f75f1dc71976a05907a0c6c7cfca).~~ _(sorry, wrong link, ugh! Here is the right one: [Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e9433a0de1bcf4dbd8888c0e514878d3))_

Unless there is another way to move out of `self` when `Self: Drop`?

---

<div class="post-metadata">

**Author:** ![jbe](https://avatars.discourse-cdn.com/v4/letter/j/f6c823/32.png) [@jbe](https://users.rust-lang.org/u/jbe)\
**Post date:** [August 15, 2022, 1:17pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/19 "2022-08-15T13:17:08Z")

</div>

> [@jbe](#):
>
> Unless there is another way to move out of `self` when `Self: Drop`?

I guess I could do this:

```rust
    pub fn finalize(self) -> BufReadGuard<T> {
        let mut this = std::mem::ManuallyDrop::new(self);
        BufReadGuard::new(take(&mut this.buffer), this.recycler.clone())
    }

```

([Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7fecee8adee188f8d41a7a3c4f58d689))

* * *

But wouldn't this be even nicer?

```rust
    pub fn finalize(self) -> BufReadGuard<T> {
        let this = std::mem::ManuallyDrop::new(self);
        BufReadGuard::new(this.buffer, this.recycler)
    }

```

([Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=c66c2d546da94cc1ba7dde062c3ca684))

Unfortunately:

```rust
   Compiling playground v0.0.1 (/playground)
error[E0507]: cannot move out of dereference of `ManuallyDrop<BufWriteGuard<T>>`
  --> src/main.rs:54:27
   |
54 | BufReadGuard::new(this.buffer, this.recycler)
   | ^^^^^^^^^^^ move occurs because value has type `Vec<T>`, which does not implement the `Copy` trait

error[E0507]: cannot move out of dereference of `ManuallyDrop<BufWriteGuard<T>>`
  --> src/main.rs:54:40
   |
54 | BufReadGuard::new(this.buffer, this.recycler)
   | ^^^^^^^^^^^^^ move occurs because value has type `UnboundedSender<Vec<T>>`, which does not implement the `Copy` trait

For more information about this error, try `rustc --explain E0507`.
error: could not compile `playground` due to 2 previous errors

```

I guess that's because `ManuallyDrop` is an ordinary wrapper and not some sort of language-built-in feature.

---

<div class="post-metadata">

**Author:** ![Hyeonu](https://sea1.discourse-cdn.com/flex019/user_avatar/users.rust-lang.org/hyeonu/32/7970_2.png) [@Hyeonu](https://users.rust-lang.org/u/Hyeonu)\
**Post date:** [August 15, 2022, 1:30pm UTC](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903/20 "2022-08-15T13:30:26Z")

</div>

While I agree it should be guaranteed, your example still don't leak. `mem::take()` replace the value with `Default::default()`, and that `Vec::default()` will be dropped after the `<BufWriteGuard as Drop>::drop()` method returns just like any other fields.

[Next page](https://users.rust-lang.org/t/guarantee-that-vec-default-does-not-allocate/79903.md?page=2)
