What about `Impl Copy for Arc<T> where T: !Drop`?

You know, it doesn't allow to impl Copy for T which impl Drop.
But why not impl Copy for Box and Arc which T isn't impl Drop?

In my cases, I spend a lot of time to clone each Arc-ed variable before clone into closure, even Arc's inner value implmented Copy, but Arc is not.

I believe Arc's drop is safe to call multiple time.

Copying is always a raw bitwise copy. This is impossible to implement correctly for types that manage any sort of allocation, because it would lead to a double-free.

Cloning a Box doesn't only clone the inner value, it also creates a separate allocation. Cloning an Arc doesn't just duplicate the pointer, it also increments the reference count.

Your beliefs are wrong.


Indeed. The following code demonstrates a possible side-effect of Arc::clone:

use std::sync::Arc;

fn main() {
    let arc = Arc::new(());
    //let cloned = arc.clone(); // uncommenting this causes a panic below
    let _ = Arc::into_inner(arc).unwrap();


When a type is Copy, then copying the value must not have any side-effect. So Arc<T> can't implement Copy, even if T: !Drop.

While dropping the value contained in the Arc is not a problem if “T: !Drop” (by which you likely actually mean mem::needs_drop::<T>() == false or “T has no drop glue”[1]) an Arc<T> comes with two things that need to be destructed: The value T, and the allocation that holds T and the reference counters. The latter is what prohibits any Arc<T>: Copy implementations in general.

Something you can do with a type T: Copy is to avoid usage of Arc<T> entirely, an just use (and copy) T directly; at least if T isn’t too large for this to be efficient enough.

  1. which in turn is arguably something that has no precedent of appearing in trait bounds in any form, and typically T: Copy is used in cases where we want to specialize on something comparable ↩︎


I count three things there :laughing:.

  • The value T.
  • The allocation (which also applies in case of Box).
  • The reference counters (which apply to Arc and Rc, but not to Box).

Right… but the reference counters don’t need to be destructed (they’re just two integers, either in Cells or atomic); and the allocation I mentioned holds both T and the reference counters together.


Why in your use case do you clone Arcs, is it a requirement? Can you pass &T in a local scope in many of these cases?

I had to take data in global scope, but I didn't tried local scoping yet. I need some tests.

Yes, that's right but my case is for T: !Copy, so...

Because of the way Arc<T> works, it must always have a destructor, and having a destructor prohibits a type from implementing Copy.

If the cost of incrementing an Arc's reference count is having a tangible impact on your code's performance then it's probably time to take a step back and revisit the design so that a single atomic increment isn't becoming a bottleneck.

Out of curiosity, how did you determine your code spends a lot of time in the Arc::clone() call?


I'm not sure if the OP meant that the CPU spends time or whether they meant it's tedious to type .clone() and declare new variables all time (which I also sometimes find tedious when passing cloned Arcs to closures).

1 Like

In ancient times Rust used to have a compiler backdoor for Rc and Gc that makes them Copy. The reason for eventually getting rid of that is to make Copy always trivial (pure memcpy calls), which is also why you need a compiler backdoor.

Maybe my poor English makes you confused, but what i'm saying spend a lot of time to clone Arc is, I spend my own time to write it and to fight with compiler, and make block before closure to make a clone.

1 Like

Ahaha I actually tried to make a fork of rustc to make it possible, but I didn't know there were backdoor before. Interesting!

Note that it is not possible to just add that exception back in today, because the standard library code, and probably other libraries, though I can't name any of them, will often assume that if a type is Copy than it can be simply copied, and the compiler doesn't know anything about that.


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.