Arc<> In The Wild

I'm storing an Arc<HashMap<String, Thing>> in a struct impl and want to return an Arc<Thing> from a method (by doing a lookup) on the HashMap, by reusing the same Arc (because it won't work otherwise) - is that possible?

No. Arc is a pointer, and it has to know the size of T. You cannot transmute T.

Why do you say it won't work otherwise?

1 Like

Ah, yes, must know the size of the heap data.

I can't construct a new Arc with a wrapped ref without getting into lifetime issues that put me down this path in the first place.

I'll probably just have to have the slightly less ergonomic API of returning Arc<HashMap<String, Thing>> and having clients do the lookup.

Note that this isn't specific to Arc<T> - if you tried to return it as any owned value at all, this wouldn't work, and for much the same reason.

Rather than borrowing, you might want to think about restructuring the ownership hierarchy of the borrowed data, if that's feasible. If it is, then perhaps you could avoid using Arc<T>altogether.

Alternately, if Arc<Thing> is ultimately what you want to be passing around, then you should store Arc<Thing> as the values in your HashMap.

4 Likes

It's not because the data is held by a struct and I we can't prove that the struct has static lifetime. The data is iniited at startup and last for the life of the program.

Using OnceLock was suggested here, but would require substantial refactoring.

Box::leak is another possibility and might have been better than what I did.

I do store Arc<Thing> as the values in the HashMap. That's exactly what it is - the OP shows that.

But since an Arc's value can't change, I couldn't return an Arc<&Thing> without creating a new Arc. And you can't do that without cloning, so then I lose the advantage I was going for all along: not having to clone.

I should give more detail: The data is a map of dates to temporal data. A master cache holds the entire data set - years worth of data - and clients are typically after a few days at a time. So cloning on each get() is very wasteful.

And that's where the code is now, after a 3-hour refactoring to use Arc. :frowning:

I will have to explore Box::leak, or using OnceLock after all...

Cloning an Arc increments the refcount. It doesn't clone the pointed data. That's the whole point of Arc.

3 Likes

Your original post says Arc<HashMap<String, Thing>>. I am suggesting changing this to HashMap<String, Arc<Thing>>.

(Or possibly Arc<HashMap<String, Arc<Thing>>> if you need to share both the entire HashMap and individual values.)

The idea is that you would return Arc<Thing> (not Arc<&Thing>). You would do this by cloning the Arc, which just returns a new pointer to the same value. (Arc::clone doesn’t allocate, or create a new Thing. It’s just like returning a shared &Thing pointer, except that it also bumps the reference count. The only thing that gets copied is a pointer.)

Note: To avoid confusion, it would be useful to share some actual (or simplified) code, including what you already tried and why it doesn’t work for you.

9 Likes

You are correct that I've caused confusion by simplifying the example! Apologies to the group.

You also gave me a great idea with the notion of moving the scope of the Arcs; alas, due to my oversimplification, that doesn't quite work either.

I will now lay out all the relevant details.

Thing is actually a Vec<DailyHistory>, and the get accessor requires potentially filtering the contents of that Vec based on some criteria.

My goal was to be able to return a new Vec without having to clone the DailyHistorys.

So, to be clear (now), the data structure is HashMap<NaiveDate, Vec<DailyHistory>>.

Also, although using Box::leak would work, in the long-term, I don't really want to leak. Now, the program needs to be restarted daily to fetch new daily data, but, in the long-term, ideally, it would re-init for a new day, dropping the old data. (Therefore static is also not ideal.)

You can keep moving the Arc inward as far as you want. If you make your data structure a HashMap<NaiveDate, Vec<Arc<DailyHistory>>>, then you can still just clone the Arcs after filtering.

5 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.