|
|
Subscribe / Log in / New account

Memory safety is still considered nice-to-have?

Memory safety is still considered nice-to-have?

Posted Aug 20, 2024 18:09 UTC (Tue) by NYKevin (subscriber, #129325)
In reply to: Memory safety is still considered nice-to-have? by excors
Parent article: FreeBSD considers Rust in the base system

I wouldn't characterize unique_ptr as equivalent to T. It is closer to Box<Option<T>>, but it implicitly calls Option::unwrap_unchecked() when you dereference it. Which would be horrible by Rust standards, but is very meh by C++ standards.


to post comments

Memory safety is still considered nice-to-have?

Posted Aug 21, 2024 11:13 UTC (Wed) by excors (subscriber, #95769) [Link]

Technically that's correct, but I meant (but didn't really say) that idiomatically, I think you'd typically use std::unique_ptr<T> in the same places you'd simply use T in Rust.

E.g. in C++ you may avoid using a raw T because it has an expensive copy constructor and no move constructor, or because you suspect it might and its documentation doesn't provide a clear answer, or you're writing generic code so you can't know in advance. It's safer to wrap everything in pointers to avoid surprising performance issues, whereas in Rust you know it's always possible and cheap to move any T. In particular I think it's fairly common to use std::vector<std::unique_ptr<T>> to ensure there's no unwanted copying when the vector grows, whereas in Rust you'd just use Vec<T>.

std::unique_ptr<T> can be used in things like the pimpl idiom, i.e. a public class's member variables where the definition of T is private and should not be accessible to users of the class. You don't need to do that in Rust, since a public struct can have fields with private types and the visibility rules keep the implementation hidden. (That does mean the private type becomes part of the public ABI, but Rust doesn't provide ABI stability anyway.)

std::unique_ptr<T> can be used for members with delayed initialisation, where you don't want to (or can't) call the default constructor of T, so you leave the unique_ptr empty until it's initialised later. In Rust you can use Option<T> instead, which admittedly isn't T but it's much closer to T than to Box<T>, since there's no heap allocation.

std::unique_ptr<T> can be used for local variables when T is too large to comfortably go on the stack. In Rust, tough luck - when you create a new Box<T>, the compiler's probably going to construct a temporary T on the stack before memcpying it into the heap. You'll need to make sure your environment has large stacks, and then you might as well just keep T on the stack and skip the boxing. (And avoid defining large structs; e.g. never use large statically-sized arrays, use Vec instead.)

There are cases where you'd still want a singly-owned Box<T>, like polymorphic types (Box<dyn Trait>) or recursive types (binary trees etc), but I suspect that's rare compared to all the other uses for std::unique_ptr that shouldn't be translated into a Box.


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds