Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> then use unsafe/raw pointers

Even if I manage to extract an unsafe pointer from that Rust collection, I don’t know for how long will it work. For C++ collections, iterator invalidation rules tell me that.




> Even if I manage to extract an unsafe pointer from that Rust collection,

It's easy, just get the & or &mut to the value (as if you were acessing it), and cast it to respectively * const or * mut.

> I don’t know for how long will it work. For C++ collections, iterator invalidation rules tell me that.

It's the same in Rust. Whenever the iterator would be invalidated in C++, the pointer you stashed above might point to the wrong place. This is not usually documented in Rust, because its borrow rules prevent you from stashing a reference while the collection mutates, but once you start playing with raw pointers, the borrow checker gets out of the way (references have a lifetime, pointers don't).

You just have to be careful when casting the pointer back to a mutable ref ("unsafe { &mut *ptr }" is the trick, see the documentation for std::mem::transmute): mutable references are like C99's "restrict", so you should make sure to only ever have one live for each pointer at every moment, otherwise you're in undefined behavior land.

----

Anyway, going back to the parent comment, you said "Values are not small, can’t afford duplicating them". Might I suggest keeping the values in a Box<T> then, and making both collections point to the box? That way, you don't have to worry about a mutation in one of the collections invalidating the pointer, since the contents of a Box won't move in memory.

And in fact, the usual Rust style for keeping a value in more than one collection would be to use a Rc<T>, which is basically a Box with a reference counter. That way, you don't need to play with raw pointers, and have no risk of a misstep. You pay the cost of incrementing/decrementing the reference counter only when adding/removing from the collection, and the reference counter is small.


> keeping the values in a Box<T> > for keeping a value in more than one collection would be to use a Rc<T>

Indeed, both methods are simple and elegant ways to approach the problems.

The bad thing with both of them is performance.

Box<T> means when I need to iterate through all values in a collection, I’ll get random memory access for each item. Rc<T> is even worse, not only it’s RAM read latency per item, also ref.counting overhead per item (AFAIK even when reading stuff).


> also ref.counting overhead per item (AFAIK even when reading stuff).

That's the beauty of the borrow checker: no, there's no reference counting overhead when reading stuff. The borrow checker guarantees that the reference you used to access the value won't go away until you're done with it, so it doesn't have to increment the reference counter.


You'd have to box your values. And if you didn't want to do that, then I'd just used the indexing method mentioned elsewhere in this thread. I've used such things in performance critical code.


> the indexing method mentioned elsewhere in this thread

https://news.ycombinator.com/item?id=15180649


> For C++ collections, iterator invalidation rules tell me that.

The iterator invalidation rules in Rust are straightforward, more straightforward than those in C++. They have to be, because the compiler actually checks them.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: