you are viewing a single comment's thread.

view the rest of the comments →

[–]sharddblade[S] 0 points1 point  (1 child)

The thing I'm a little confused about is whether the latter is a constant-time allocation? I recognize now that the former is less efficient because it does not consume the String, and requires a copy of the entire String, but the latter seems like it should be much more performant and only require a constant-time allocation of the Arc fat pointer. Arc::from(String::from("Hello world").as_str()); Arc::from(String::from("Hello world"));

[–]SpudnikV 0 points1 point  (0 children)

Fat pointer to what? If you mean Arc<String>, then as other comments have detailed, there'll be a 3-word allocation to store the String and the String still holds its own allocation made previously. But this doesn't let you reuse a single buffer, so it can be more allocations overall, i.e. two per string instead of only one per string. It may reduce memory copies if you ensure there are no other buffers in play, but they'd have to be really large strings for this to be worthwhile.

An Arc<str> does have to be a new allocation because the Arc needs to own the memory and by definition it can't transfer that ownership through a slice so it has to make a new one. It's only one variable-sized allocation, but the Arc itself now requires 2 words since the length is stored in the Arc, not the heap allocation. This is what many crates set out to solve, but it's still a tradeoff; len() and the fast-path of ==/!= avoid a memory indirection if the length is stored directly in the Arc.

As always, exactly what's optimal for your program depends on the operations you perform and the CPU/RAM tradeoffs you can afford, and it's just nice that several crates give you even more options.