What is the use of into_boxed_slice() methods?
Asked Answered
S

2

17

Looking at the methods available for Vec<T> I stumbled across

into_boxed_slice(self) -> Box<[T]>

String also has such a method (into_boxed_str(self)). The usefulness of having Deref for Vec<T>/String that allows them to be treated like a shared slice (&[T]) is obvious, but I don't see any use for an owned slice (Box<[T]>) except, perhaps, FFI. The Rust GitHub repo only uses into_boxed_slice() in a handful of cases.

Since methods for creating boxed slices are available in std and this container is listed on its main page, I thought that I might be missing something useful about it. What are cases where I should use an owned slice in favor of a Vec<T> or a String?

Skew answered 21/9, 2016 at 11:44 Comment(7)
Not sure if it's the reason, but Box<[T]> and Box<str> have one less pointer-sized integer as they don't need a capacity — they can't be resized.Archaeornis
I thought about this, but it doesn't strike me as a reason enough to have a dedicated container either.Skew
I'm not sure what you mean by "dedicated container". It's just a combination of existing types - Box and [T] or str. It's not really that different from a Box<Trait>.Archaeornis
You're right, though it is listed in the main page of std, which gives it a feeling of some nobility :). That's what got me interested in it.Skew
I'd guess it's probably just meant to be a cheap, safe way of getting the underlying heap pointer. Effectively an "into_inner" method. Probably provided in case somebody really wants to own the underlying buffer for reasons that weren't considered very strongly because it's trivial to implement.Choi
Otherwise, to avoid intermediate allocations, you have to go through unsafe shenanigans like Box::from_raw(&mut vec[..] as *mut [T]), and then manually forget the Vec, which is just unpleasant. It's nicer to just provide a safe alternative.Choi
I saw the implementation and it makes sense; I'd still like to know some practical use of owning the inner buffer, though (if there are other than FFI).Skew
K
17

The big reason for using into_boxed_slice() is that a boxed slice takes up only as much memory as:

  • The underlying data itself
  • A length field that gives the total length of the data

When using a standard Vec it is possible, and common, for the Vec to obtain more memory than what it actually needs to avoid having to allocate more memory every time a new element is added. That space is essentially unused. You can find out how much extra memory is being used by comparing Vec::len() versus Vec::capacity().

The main place that I have found the into_boxed_slice() function useful is in an in-memory file cache. I load the file into memory using a Vec for simplicity, but once the file is loaded, I no longer need to add or remove elements. So I convert it to a boxed slice using into_boxed_slice(). There would be other ways to achieve the same thing, but in this case the single function call is easier. I like the boxed slice type (as opposed to a Vec) because it clearly signals the intent that the cached file is not meant to modified.

Note: you can actually still use a Vec without the extra overhead by calling Vec::shrink_to_fit(), which will remove the extra allocated elements from the Vec.

Kinetics answered 26/9, 2016 at 2:42 Comment(2)
If I can remember correctly, into_boxed_slice() calls shrink_to_fit() too. It's a valid answer; I was hoping to learn some hidden benefits, but there just might not be any. I'll accept it if nothing surprising comes up soon.Skew
shrink_to_fit doesn't guarantee that length will equal capacity after it returns. The docs say it will shrink "as much as possible": doc.rust-lang.org/std/vec/struct.Vec.html#method.shrink_to_fit into_boxed_slice internally does use into_boxed_slice, but also guarantees the returned slice will be of length vec.len(), so it goes beyond the guarantees of shrink_to_fitPenury
C
1

I have an application where I have a Vec of tens of thousands of elements, each of which could be a Vec or a Box<[T]> so I save hundreds of thousands of bytes by using into_boxed_slice.

Clausewitz answered 4/5, 2021 at 3:37 Comment(2)
I mean you save by not needing the capacity field in the Vec by having a slice [T]? Is that the reason?Aerometeorograph
@Aerometeorograph Yes, that's the reason. So 8 bytes per Vec (or String) is saved on a 64 bit architecture.Pavis

© 2022 - 2024 — McMap. All rights reserved.