I was playing with some code in rust, and was trying to see how much overhead coming from Arc, especially when it should be zero cost abstraction.
In first example, it is obvious that Arc is useless in this case, and I was checking if Rust will do Zero Cost Abstraction, however here what I’ve got in assembly:
on the memory aspect, Arc, and any reference-counted smart pointer types, including C++'s shared_ptr, can NEVER have zero memory overhead, since the bookkeeping information (called "control block" in C++, mainly the strong count and weak count) must be stored somewhere.
rust's implementation stores them along side the data (a.k.a. colocated), and Arc is a thin pointer [1], while C++ uses a separate allocation for them, and C++ shared_ptr is a wide pointer. (although C++'s make_shared() guarantees a single colocated heap allocation, std::share_ptr still stores the data pointer and control block pointer separately).
for the runtime overhead, dereferencing an Arc, i.e. convert from Arc<T> to &T just needs to offset the pointer with a small constant, which is basically a free operation in modern CPU ISA. and once you get the data pointer, it's indistinguishable from any data pointers of the same type.
the only real runtime "overhead" of Arc is when you update the reference counter by manipulating the ownerships, especially in contentious concurrent scenarios. but you are not doing this in critical paths anyway.
I don't know what's your expectation or definition for "zero cost abstration", but Arc is practically zero cost to me, as a heap allocated smart pointer.
That's the case if have a Arc<T>. If you have a &Arc<T> that's basically a pointer pointing to a pointer, so you have to perform a read from the first one in order to get a &T.