Skip to content

Q039. What does Arc<T> provide, and when should you use it?

Short Answer

Arc<T> provides shared ownership of one heap-allocated T through atomic reference counting. Cloning an Arc creates another owner of the same value; the value is dropped after the last strong owner is dropped. Use it when multiple threads or independently owned tasks must keep the same value alive. Arc solves ownership and lifetime sharing, not mutation or thread safety by itself.

Deep Dive

Ordinary ownership requires one owner, and borrowed references are limited by the owner's lifetime. Arc is useful when no single participant naturally owns the value long enough, such as shared application state captured by several spawned tasks.

Arc::clone is shallow: it does not clone T. It creates another handle to the same allocation and increments the strong count. Shared immutable access works through Deref<Target = T>. Mutation requires an additional strategy such as Mutex, RwLock, atomics, interior mutability provided by T, or message passing.

Prefer a borrow when a clear lexical owner exists. Prefer Rc for shared ownership confined to one thread. Use Arc only when ownership must cross thread boundaries or an API requires Send.

Internal Model

An Arc handle points to an allocation containing reference-count metadata and T. Strong references keep T alive. Weak references keep the allocation metadata alive without keeping T alive.

The counts are updated atomically so clones and drops can occur safely from different threads. Those atomic operations add synchronization cost compared with a borrow or Rc, but accessing T through an existing Arc does not increment the count.

Example

rust
use std::sync::Arc;
use std::thread;

fn main() {
    let names = Arc::new(vec!["matching", "risk", "market-data"]);
    let worker_names = Arc::clone(&names);

    let worker = thread::spawn(move || {
        println!("worker sees {} services", worker_names.len());
    });

    println!("main sees {} services", names.len());
    worker.join().unwrap();
}

Common Mistakes

  • Saying Arc::clone performs a deep clone of T.
  • Using Arc when a normal borrow has a clear and sufficient lifetime.
  • Assuming Arc<T> permits safe concurrent mutation of any T.

Follow-ups

  • How are strong and weak reference counts different?
  • When should Rc<T> be preferred over Arc<T>?
  • How can reference cycles prevent an Arc allocation from being released?

References

  • Rust Standard Library
  • The Rust Programming Language